---
# System prepended metadata

title: 2023 程式設計 抄襲分析

---

# 2023 程式設計 考試抄襲分析

## 如何抓抄襲?

我們採用史丹佛大學開發的 MOSS(https://theory.stanford.edu/~aiken/moss/)，這是一套用來專門分析程式碼抄襲的工具。此工具會檢測同學之間的程式碼相似程度，且此工具在更換程式順序、變數名稱下仍可以正確檢測。

然而，此套工具也明確說明「僅供參考」，因此仍需要由助教進行二次確認。但相比一個個程式點開來檢查，節省下非常多的時間。

## 抄襲檢測流程

1. 將學生的程式碼皆上傳至 MOSS
2. 若該次考試有提供範例程式，將此範例程式設為排除項目上傳至 MOSS
3. MOSS 產生結果網頁，如下圖:
<!-- ![image](https://hackmd.io/_uploads/BJTzDgnU0.png) -->
![螢幕擷取畫面 2024-06-28 164049](https://hackmd.io/_uploads/SJQS9rgP0.png)

在結果報告中，會顯示不同色塊，代表相似性高的片段
![螢幕擷取畫面 2024-07-01 232928](https://hackmd.io/_uploads/B1ICiSgv0.png)
![image](https://hackmd.io/_uploads/Hy6NnrxvR.png)


4. 由助教群討論檢視 MOSS 較前面的結果，若助教群多數認為有抄襲嫌疑，將抄襲的檢測結果與抄襲判斷交給老師做最後決定，如下圖:
<!-- ![image](https://hackmd.io/_uploads/B1odcl3IR.png) -->
![螢幕擷取畫面 2024-06-28 165455](https://hackmd.io/_uploads/S1KYqSewR.png)

## 抄襲情形

### 程設一期中考 共 2 組

- 有發現有一組人抄襲網路上相同的程式碼
- 一組程式邏輯非常相似

### 程設一期末考 共 6 組

- 在計算分數與踩地雷等兩題，發現多組程式邏輯相似，變數命名也相似的程式碼。但因為題目較容易，程式碼行數短，故沒有認定為嚴重抄襲

![image](https://hackmd.io/_uploads/rJvujNgwR.png)
![image](https://hackmd.io/_uploads/Byvco4ePC.png)

### 程設二期中考 共 0 組

### 程設二期末考 共 1 組

- 在核心函式上完全相同，但最後兩位同學在該題獲得分數差異甚大，分別為 5 分與 25 分

![image](https://hackmd.io/_uploads/HJc4MrgDR.png)

## 現今大型語言模型之解題能力

隨著大型語言模型（LLM）變得普及，我們預期會有越來越多的同學使用 LLM 輔助進行解題，其中 LLM 對於複雜題目的直接解題能力，將直接影響到 LLM 對於輔助行為的涉入程度（僅從語法補全、函數實作，乃至於直接依照指令完成整份程式）。

此次，助教使用目前最廣泛被一般大眾使用的 LLM 服務 OpenAI ChatGPT (GPT-4o) 嘗試在不對 LLM 生成之程式碼進行修改的情況下，以自然語言指令的方式引導其完成程設二期末考之其中一題。

![截圖 2024-07-01 晚上11.16.51](https://hackmd.io/_uploads/ryMOdrePR.png)
![截圖 2024-07-01 晚上11.17.39](https://hackmd.io/_uploads/HkgiurxvC.png)
![截圖 2024-07-01 晚上11.18.00](https://hackmd.io/_uploads/S1Lh_Hxv0.png)

此題涉及：

1. 利用 libcurl 抓取網頁資訊
2. 解析出網頁中的所需資訊並進行統計
3. 依統計資訊產生一張 BMP 圓餅圖

雖然 ChatGPT 具有直接瀏覽網頁的功能，但因該網頁大小過大（超過 1.5MB），會遇到 LLM 詞元（token）上限問題，因此對於網頁的特徵工程由人類進行，再指示 LLM 編寫程式尋找特定字詞當作起始位置再解析特定詞語。

完整過程：https://chatgpt.com/share/aaa2b756-d6ad-462f-a87f-865bf2ae371e

解題的順序由人類決定從「2. 解析出網頁中的所需資訊並進行統計」開始：

> Write a C program, by giving a HTML file, find the line which starts with var resultList =, and then find all "SCORE":"N" where N is a one-digit number (0, 1, 2, ...), and output the count of each N.

:::spoiler Code 1
```c=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_LINE_LENGTH 1024

int main() {
    FILE *file;
    char line[MAX_LINE_LENGTH];
    int score_count[10] = {0};

    file = fopen("input.html", "r");
    if (file == NULL) {
        perror("Error opening file");
        return EXIT_FAILURE;
    }

    // Find the line starting with "var resultList ="
    while (fgets(line, MAX_LINE_LENGTH, file) != NULL) {
        if (strncmp(line, "var resultList =", 16) == 0) {
            break;
        }
    }

    if (feof(file)) {
        fprintf(stderr, "Error: Line starting with 'var resultList =' not found\n");
        fclose(file);
        return EXIT_FAILURE;
    }

    // Find all occurrences of "SCORE":"N" where N is a one-digit number
    char *pos = line;
    while ((pos = strstr(pos, "\"SCORE\":\"")) != NULL) {
        pos += 9; // Move past "\"SCORE\":\""
        if (isdigit(*pos)) {
            int score = *pos - '0';
            if (score >= 0 && score <= 9) {
                score_count[score]++;
            }
        }
        pos++;
    }

    fclose(file);

    // Output the count of each score
    for (int i = 0; i <= 9; i++) {
        printf("SCORE %d: %d\n", i, score_count[i]);
    }

    return EXIT_SUCCESS;
}
```

:::

LLM 完整地給出可以編譯並執行的 C 原始碼，但統計資訊不完整。原因是因為 LLM 不知道檔案大小的緣故，所以給出的 buffer size 不夠大，於是指示其增加大小。

> MAX_LINE_LENGTH should be larger (maybe 8MB?)

:::spoiler Code 2

```c=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_LINE_LENGTH 8 * 1024 * 1024 // 8MB

int main() {
    FILE *file;
    char *line;
    int score_count[10] = {0};

    line = (char *)malloc(MAX_LINE_LENGTH * sizeof(char));
    if (line == NULL) {
        perror("Error allocating memory");
        return EXIT_FAILURE;
    }

    file = fopen("input.html", "r");
    if (file == NULL) {
        perror("Error opening file");
        free(line);
        return EXIT_FAILURE;
    }

    // Find the line starting with "var resultList ="
    while (fgets(line, MAX_LINE_LENGTH, file) != NULL) {
        if (strncmp(line, "var resultList =", 16) == 0) {
            break;
        }
    }

    if (feof(file)) {
        fprintf(stderr, "Error: Line starting with 'var resultList =' not found\n");
        fclose(file);
        free(line);
        return EXIT_FAILURE;
    }

    // Find all occurrences of "SCORE":"N" where N is a one-digit number
    char *pos = line;
    while ((pos = strstr(pos, "\"SCORE\":\"")) != NULL) {
        pos += 9; // Move past "\"SCORE\":\""
        if (isdigit(*pos)) {
            int score = *pos - '0';
            if (score >= 0 && score <= 9) {
                score_count[score]++;
            }
        }
        pos++;
    }

    fclose(file);
    free(line);

    // Output the count of each score
    for (int i = 0; i <= 9; i++) {
        printf("SCORE %d: %d\n", i, score_count[i]);
    }

    return EXIT_SUCCESS;
}
```

:::

LLM 也適當的調整了相應的位置。

接著開始讓 LLM 畫 BMP：

> Ok, then make it plot a bmp pie chart too


:::spoiler Code 3

```c=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#define MAX_LINE_LENGTH 8 * 1024 * 1024 // 8MB
#define WIDTH 800
#define HEIGHT 800
#define CENTER_X (WIDTH / 2)
#define CENTER_Y (HEIGHT / 2)
#define RADIUS (WIDTH / 3)

typedef struct {
    unsigned char b;
    unsigned char g;
    unsigned char r;
} Pixel;

typedef struct {
    unsigned int width;
    unsigned int height;
    Pixel *pixels;
} Bitmap;

void save_bmp(const char *filename, Bitmap *bmp) {
    FILE *f;
    unsigned char bmpfileheader[14] = {
        'B', 'M',           // BMP signature
        0, 0, 0, 0,         // File size
        0, 0,               // Reserved
        0, 0,               // Reserved
        54, 0, 0, 0         // Data offset
    };
    unsigned char bmpinfoheader[40] = {
        40, 0, 0, 0,        // Info header size
        0, 0, 0, 0,         // Width
        0, 0, 0, 0,         // Height
        1, 0,               // Planes
        24, 0,              // Bits per pixel
        0, 0, 0, 0,         // Compression
        0, 0, 0, 0,         // Image size (can be 0 for BI_RGB)
        0, 0, 0, 0,         // X pixels per meter
        0, 0, 0, 0,         // Y pixels per meter
        0, 0, 0, 0,         // Total colors
        0, 0, 0, 0          // Important colors
    };

    unsigned int filesize = 54 + 3 * bmp->width * bmp->height;
    bmpfileheader[2] = (unsigned char)(filesize);
    bmpfileheader[3] = (unsigned char)(filesize >> 8);
    bmpfileheader[4] = (unsigned char)(filesize >> 16);
    bmpfileheader[5] = (unsigned char)(filesize >> 24);

    bmpinfoheader[4] = (unsigned char)(bmp->width);
    bmpinfoheader[5] = (unsigned char)(bmp->width >> 8);
    bmpinfoheader[6] = (unsigned char)(bmp->width >> 16);
    bmpinfoheader[7] = (unsigned char)(bmp->width >> 24);
    bmpinfoheader[8] = (unsigned char)(bmp->height);
    bmpinfoheader[9] = (unsigned char)(bmp->height >> 8);
    bmpinfoheader[10] = (unsigned char)(bmp->height >> 16);
    bmpinfoheader[11] = (unsigned char)(bmp->height >> 24);

    f = fopen(filename, "wb");
    fwrite(bmpfileheader, 1, 14, f);
    fwrite(bmpinfoheader, 1, 40, f);

    for (int i = 0; i < bmp->height; i++) {
        fwrite(bmp->pixels + (bmp->width * (bmp->height - i - 1)), 3, bmp->width, f);
    }
    fclose(f);
}

void draw_pie_segment(Bitmap *bmp, double start_angle, double end_angle, Pixel color) {
    for (int y = 0; y < bmp->height; y++) {
        for (int x = 0; x < bmp->width; x++) {
            int dx = x - CENTER_X;
            int dy = y - CENTER_Y;
            double distance = sqrt(dx * dx + dy * dy);
            if (distance <= RADIUS) {
                double angle = atan2(dy, dx) * 180 / M_PI;
                if (angle < 0) angle += 360;
                if (angle >= start_angle && angle <= end_angle) {
                    bmp->pixels[y * bmp->width + x] = color;
                }
            }
        }
    }
}

int main() {
    FILE *file;
    char *line;
    int score_count[10] = {0};

    line = (char *)malloc(MAX_LINE_LENGTH * sizeof(char));
    if (line == NULL) {
        perror("Error allocating memory");
        return EXIT_FAILURE;
    }

    file = fopen("input.html", "r");
    if (file == NULL) {
        perror("Error opening file");
        free(line);
        return EXIT_FAILURE;
    }

    // Find the line starting with "var resultList ="
    while (fgets(line, MAX_LINE_LENGTH, file) != NULL) {
        if (strncmp(line, "var resultList =", 16) == 0) {
            break;
        }
    }

    if (feof(file)) {
        fprintf(stderr, "Error: Line starting with 'var resultList =' not found\n");
        fclose(file);
        free(line);
        return EXIT_FAILURE;
    }

    // Find all occurrences of "SCORE":"N" where N is a one-digit number
    char *pos = line;
    while ((pos = strstr(pos, "\"SCORE\":\"")) != NULL) {
        pos += 9; // Move past "\"SCORE\":\""
        if (isdigit(*pos)) {
            int score = *pos - '0';
            if (score >= 0 && score <= 9) {
                score_count[score]++;
            }
        }
        pos++;
    }

    fclose(file);
    free(line);

    // Create a bitmap for the pie chart
    Bitmap bmp;
    bmp.width = WIDTH;
    bmp.height = HEIGHT;
    bmp.pixels = (Pixel *)malloc(WIDTH * HEIGHT * sizeof(Pixel));
    if (bmp.pixels == NULL) {
        perror("Error allocating memory for bitmap");
        return EXIT_FAILURE;
    }

    // Fill the bitmap with white color
    for (int i = 0; i < WIDTH * HEIGHT; i++) {
        bmp.pixels[i].r = 255;
        bmp.pixels[i].g = 255;
        bmp.pixels[i].b = 255;
    }

    // Colors for the pie segments
    Pixel colors[10] = {
        {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0},
        {0, 255, 255}, {255, 0, 255}, {128, 0, 0}, {0, 128, 0},
        {0, 0, 128}, {128, 128, 0}
    };

    // Calculate total scores
    int total_scores = 0;
    for (int i = 0; i <= 9; i++) {
        total_scores += score_count[i];
    }

    // Draw the pie chart segments
    double start_angle = 0.0;
    for (int i = 0; i <= 9; i++) {
        if (score_count[i] > 0) {
            double end_angle = start_angle + (score_count[i] / (double)total_scores) * 360.0;
            draw_pie_segment(&bmp, start_angle, end_angle, colors[i]);
            start_angle = end_angle;
        }
    }

    // Save the bitmap to a file
    save_bmp("pie_chart.bmp", &bmp);

    // Free allocated memory
    free(bmp.pixels);

    // Output the count of each score
    for (int i = 0; i <= 9; i++) {
        printf("SCORE %d: %d\n", i, score_count[i]);
    }

    return EXIT_SUCCESS;
}
```

:::

該程式確實可以輸出具有正確標頭與圓餅圖的 BMP，但其繪圖方向與起始角度與題目要求不同。
於是我們對其指示圓餅圖的方向與起始位置：

> Let the pie chart draw counterclockwise starting from 90 degrees.

:::spoiler Code 4

```c=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#define MAX_LINE_LENGTH 8 * 1024 * 1024 // 8MB
#define WIDTH 800
#define HEIGHT 800
#define CENTER_X (WIDTH / 2)
#define CENTER_Y (HEIGHT / 2)
#define RADIUS (WIDTH / 3)

typedef struct {
    unsigned char b;
    unsigned char g;
    unsigned char r;
} Pixel;

typedef struct {
    unsigned int width;
    unsigned int height;
    Pixel *pixels;
} Bitmap;

void save_bmp(const char *filename, Bitmap *bmp) {
    FILE *f;
    unsigned char bmpfileheader[14] = {
        'B', 'M',           // BMP signature
        0, 0, 0, 0,         // File size
        0, 0,               // Reserved
        0, 0,               // Reserved
        54, 0, 0, 0         // Data offset
    };
    unsigned char bmpinfoheader[40] = {
        40, 0, 0, 0,        // Info header size
        0, 0, 0, 0,         // Width
        0, 0, 0, 0,         // Height
        1, 0,               // Planes
        24, 0,              // Bits per pixel
        0, 0, 0, 0,         // Compression
        0, 0, 0, 0,         // Image size (can be 0 for BI_RGB)
        0, 0, 0, 0,         // X pixels per meter
        0, 0, 0, 0,         // Y pixels per meter
        0, 0, 0, 0,         // Total colors
        0, 0, 0, 0          // Important colors
    };

    unsigned int filesize = 54 + 3 * bmp->width * bmp->height;
    bmpfileheader[2] = (unsigned char)(filesize);
    bmpfileheader[3] = (unsigned char)(filesize >> 8);
    bmpfileheader[4] = (unsigned char)(filesize >> 16);
    bmpfileheader[5] = (unsigned char)(filesize >> 24);

    bmpinfoheader[4] = (unsigned char)(bmp->width);
    bmpinfoheader[5] = (unsigned char)(bmp->width >> 8);
    bmpinfoheader[6] = (unsigned char)(bmp->width >> 16);
    bmpinfoheader[7] = (unsigned char)(bmp->width >> 24);
    bmpinfoheader[8] = (unsigned char)(bmp->height);
    bmpinfoheader[9] = (unsigned char)(bmp->height >> 8);
    bmpinfoheader[10] = (unsigned char)(bmp->height >> 16);
    bmpinfoheader[11] = (unsigned char)(bmp->height >> 24);

    f = fopen(filename, "wb");
    fwrite(bmpfileheader, 1, 14, f);
    fwrite(bmpinfoheader, 1, 40, f);

    for (int i = 0; i < bmp->height; i++) {
        fwrite(bmp->pixels + (bmp->width * (bmp->height - i - 1)), 3, bmp->width, f);
    }
    fclose(f);
}

void draw_pie_segment(Bitmap *bmp, double start_angle, double end_angle, Pixel color) {
    for (int y = 0; y < bmp->height; y++) {
        for (int x = 0; x < bmp->width; x++) {
            int dx = x - CENTER_X;
            int dy = y - CENTER_Y;
            double distance = sqrt(dx * dx + dy * dy);
            if (distance <= RADIUS) {
                double angle = atan2(dy, dx) * 180 / M_PI + 90;
                if (angle < 0) angle += 360;
                if (angle >= start_angle && angle <= end_angle) {
                    bmp->pixels[y * bmp->width + x] = color;
                }
            }
        }
    }
}

int main() {
    FILE *file;
    char *line;
    int score_count[10] = {0};

    line = (char *)malloc(MAX_LINE_LENGTH * sizeof(char));
    if (line == NULL) {
        perror("Error allocating memory");
        return EXIT_FAILURE;
    }

    file = fopen("input.html", "r");
    if (file == NULL) {
        perror("Error opening file");
        free(line);
        return EXIT_FAILURE;
    }

    // Find the line starting with "var resultList ="
    while (fgets(line, MAX_LINE_LENGTH, file) != NULL) {
        if (strncmp(line, "var resultList =", 16) == 0) {
            break;
        }
    }

    if (feof(file)) {
        fprintf(stderr, "Error: Line starting with 'var resultList =' not found\n");
        fclose(file);
        free(line);
        return EXIT_FAILURE;
    }

    // Find all occurrences of "SCORE":"N" where N is a one-digit number
    char *pos = line;
    while ((pos = strstr(pos, "\"SCORE\":\"")) != NULL) {
        pos += 9; // Move past "\"SCORE\":\""
        if (isdigit(*pos)) {
            int score = *pos - '0';
            if (score >= 0 && score <= 9) {
                score_count[score]++;
            }
        }
        pos++;
    }

    fclose(file);
    free(line);

    // Create a bitmap for the pie chart
    Bitmap bmp;
    bmp.width = WIDTH;
    bmp.height = HEIGHT;
    bmp.pixels = (Pixel *)malloc(WIDTH * HEIGHT * sizeof(Pixel));
    if (bmp.pixels == NULL) {
        perror("Error allocating memory for bitmap");
        return EXIT_FAILURE;
    }

    // Fill the bitmap with white color
    for (int i = 0; i < WIDTH * HEIGHT; i++) {
        bmp.pixels[i].r = 255;
        bmp.pixels[i].g = 255;
        bmp.pixels[i].b = 255;
    }

    // Colors for the pie segments
    Pixel colors[10] = {
        {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0},
        {0, 255, 255}, {255, 0, 255}, {128, 0, 0}, {0, 128, 0},
        {0, 0, 128}, {128, 128, 0}
    };

    // Calculate total scores
    int total_scores = 0;
    for (int i = 0; i <= 9; i++) {
        total_scores += score_count[i];
    }

    // Draw the pie chart segments
    double start_angle = 0.0;
    for (int i = 0; i <= 9; i++) {
        if (score_count[i] > 0) {
            double end_angle = start_angle + (score_count[i] / (double)total_scores) * 360.0;
            draw_pie_segment(&bmp, start_angle, end_angle, colors[i]);
            start_angle = end_angle;
        }
    }

    // Save the bitmap to a file
    save_bmp("pie_chart.bmp", &bmp);

    // Free allocated memory
    free(bmp.pixels);

    // Output the count of each score
    for (int i = 0; i <= 9; i++) {
        printf("SCORE %d: %d\n", i, score_count[i]);
    }

    return EXIT_SUCCESS;
}
```

:::

到此之前都非常順利，LLM 成功把起始位置改成 90 度，但我們在此嘗試多次都無法使其正確地將順時針修正成逆時針，LLM 會寫出產生錯誤圖片的程式碼。
所以我們直接指示修改一行中兩個字元：

> It looks like it's now starting at 90 degrees, but still clockwise, not counterclockwise as expected.
Consider changing double angle = atan2(dy, dx) * 180 / M_PI + 90 to double angle = -atan2(dy, dx) * 180 / M_PI - 90

:::spoiler Code 5

```c=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#define MAX_LINE_LENGTH 8 * 1024 * 1024 // 8MB
#define WIDTH 800
#define HEIGHT 800
#define CENTER_X (WIDTH / 2)
#define CENTER_Y (HEIGHT / 2)
#define RADIUS (WIDTH / 3)

typedef struct {
    unsigned char b;
    unsigned char g;
    unsigned char r;
} Pixel;

typedef struct {
    unsigned int width;
    unsigned int height;
    Pixel *pixels;
} Bitmap;

void save_bmp(const char *filename, Bitmap *bmp) {
    FILE *f;
    unsigned char bmpfileheader[14] = {
        'B', 'M',           // BMP signature
        0, 0, 0, 0,         // File size
        0, 0,               // Reserved
        0, 0,               // Reserved
        54, 0, 0, 0         // Data offset
    };
    unsigned char bmpinfoheader[40] = {
        40, 0, 0, 0,        // Info header size
        0, 0, 0, 0,         // Width
        0, 0, 0, 0,         // Height
        1, 0,               // Planes
        24, 0,              // Bits per pixel
        0, 0, 0, 0,         // Compression
        0, 0, 0, 0,         // Image size (can be 0 for BI_RGB)
        0, 0, 0, 0,         // X pixels per meter
        0, 0, 0, 0,         // Y pixels per meter
        0, 0, 0, 0,         // Total colors
        0, 0, 0, 0          // Important colors
    };

    unsigned int filesize = 54 + 3 * bmp->width * bmp->height;
    bmpfileheader[2] = (unsigned char)(filesize);
    bmpfileheader[3] = (unsigned char)(filesize >> 8);
    bmpfileheader[4] = (unsigned char)(filesize >> 16);
    bmpfileheader[5] = (unsigned char)(filesize >> 24);

    bmpinfoheader[4] = (unsigned char)(bmp->width);
    bmpinfoheader[5] = (unsigned char)(bmp->width >> 8);
    bmpinfoheader[6] = (unsigned char)(bmp->width >> 16);
    bmpinfoheader[7] = (unsigned char)(bmp->width >> 24);
    bmpinfoheader[8] = (unsigned char)(bmp->height);
    bmpinfoheader[9] = (unsigned char)(bmp->height >> 8);
    bmpinfoheader[10] = (unsigned char)(bmp->height >> 16);
    bmpinfoheader[11] = (unsigned char)(bmp->height >> 24);

    f = fopen(filename, "wb");
    fwrite(bmpfileheader, 1, 14, f);
    fwrite(bmpinfoheader, 1, 40, f);

    for (int i = 0; i < bmp->height; i++) {
        fwrite(bmp->pixels + (bmp->width * (bmp->height - i - 1)), 3, bmp->width, f);
    }
    fclose(f);
}

void draw_pie_segment(Bitmap *bmp, double start_angle, double end_angle, Pixel color) {
    for (int y = 0; y < bmp->height; y++) {
        for (int x = 0; x < bmp->width; x++) {
            int dx = x - CENTER_X;
            int dy = y - CENTER_Y;
            double distance = sqrt(dx * dx + dy * dy);
            if (distance <= RADIUS) {
                double angle = -atan2(dy, dx) * 180 / M_PI - 90;
                if (angle < 0) angle += 360;
                if (angle >= start_angle && angle <= end_angle) {
                    bmp->pixels[y * bmp->width + x] = color;
                }
            }
        }
    }
}

int main() {
    FILE *file;
    char *line;
    int score_count[10] = {0};

    line = (char *)malloc(MAX_LINE_LENGTH * sizeof(char));
    if (line == NULL) {
        perror("Error allocating memory");
        return EXIT_FAILURE;
    }

    file = fopen("input.html", "r");
    if (file == NULL) {
        perror("Error opening file");
        free(line);
        return EXIT_FAILURE;
    }

    // Find the line starting with "var resultList ="
    while (fgets(line, MAX_LINE_LENGTH, file) != NULL) {
        if (strncmp(line, "var resultList =", 16) == 0) {
            break;
        }
    }

    if (feof(file)) {
        fprintf(stderr, "Error: Line starting with 'var resultList =' not found\n");
        fclose(file);
        free(line);
        return EXIT_FAILURE;
    }

    // Find all occurrences of "SCORE":"N" where N is a one-digit number
    char *pos = line;
    while ((pos = strstr(pos, "\"SCORE\":\"")) != NULL) {
        pos += 9; // Move past "\"SCORE\":\""
        if (isdigit(*pos)) {
            int score = *pos - '0';
            if (score >= 0 && score <= 9) {
                score_count[score]++;
            }
        }
        pos++;
    }

    fclose(file);
    free(line);

    // Create a bitmap for the pie chart
    Bitmap bmp;
    bmp.width = WIDTH;
    bmp.height = HEIGHT;
    bmp.pixels = (Pixel *)malloc(WIDTH * HEIGHT * sizeof(Pixel));
    if (bmp.pixels == NULL) {
        perror("Error allocating memory for bitmap");
        return EXIT_FAILURE;
    }

    // Fill the bitmap with white color
    for (int i = 0; i < WIDTH * HEIGHT; i++) {
        bmp.pixels[i].r = 255;
        bmp.pixels[i].g = 255;
        bmp.pixels[i].b = 255;
    }

    // Colors for the pie segments
    Pixel colors[10] = {
        {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0},
        {0, 255, 255}, {255, 0, 255}, {128, 0, 0}, {0, 128, 0},
        {0, 0, 128}, {128, 128, 0}
    };

    // Calculate total scores
    int total_scores = 0;
    for (int i = 0; i <= 9; i++) {
        total_scores += score_count[i];
    }

    // Draw the pie chart segments
    double start_angle = 90.0;
    for (int i = 0; i <= 9; i++) {
        if (score_count[i] > 0) {
            double end_angle = start_angle + (score_count[i] / (double)total_scores) * 360.0;
            draw_pie_segment(&bmp, start_angle, end_angle, colors[i]);
            start_angle = end_angle;
        }
    }

    // Save the bitmap to a file
    save_bmp("pie_chart.bmp", &bmp);

    // Free allocated memory
    free(bmp.pixels);

    // Output the count of each score
    for (int i = 0; i <= 9; i++) {
        printf("SCORE %d: %d\n", i, score_count[i]);
    }

    return EXIT_SUCCESS;
}
```

:::

LLM 矯枉過正，雖然修正了剛剛的錯誤，但也把正確的部分改成錯的了。
讓我們提醒它一下：

> Why change double start_angle = 0.0 to double start_angle = 90.0?

:::spoiler Code 6

```c=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#define MAX_LINE_LENGTH 8 * 1024 * 1024 // 8MB
#define WIDTH 800
#define HEIGHT 800
#define CENTER_X (WIDTH / 2)
#define CENTER_Y (HEIGHT / 2)
#define RADIUS (WIDTH / 3)

typedef struct {
    unsigned char b;
    unsigned char g;
    unsigned char r;
} Pixel;

typedef struct {
    unsigned int width;
    unsigned int height;
    Pixel *pixels;
} Bitmap;

void save_bmp(const char *filename, Bitmap *bmp) {
    FILE *f;
    unsigned char bmpfileheader[14] = {
        'B', 'M',           // BMP signature
        0, 0, 0, 0,         // File size
        0, 0,               // Reserved
        0, 0,               // Reserved
        54, 0, 0, 0         // Data offset
    };
    unsigned char bmpinfoheader[40] = {
        40, 0, 0, 0,        // Info header size
        0, 0, 0, 0,         // Width
        0, 0, 0, 0,         // Height
        1, 0,               // Planes
        24, 0,              // Bits per pixel
        0, 0, 0, 0,         // Compression
        0, 0, 0, 0,         // Image size (can be 0 for BI_RGB)
        0, 0, 0, 0,         // X pixels per meter
        0, 0, 0, 0,         // Y pixels per meter
        0, 0, 0, 0,         // Total colors
        0, 0, 0, 0          // Important colors
    };

    unsigned int filesize = 54 + 3 * bmp->width * bmp->height;
    bmpfileheader[2] = (unsigned char)(filesize);
    bmpfileheader[3] = (unsigned char)(filesize >> 8);
    bmpfileheader[4] = (unsigned char)(filesize >> 16);
    bmpfileheader[5] = (unsigned char)(filesize >> 24);

    bmpinfoheader[4] = (unsigned char)(bmp->width);
    bmpinfoheader[5] = (unsigned char)(bmp->width >> 8);
    bmpinfoheader[6] = (unsigned char)(bmp->width >> 16);
    bmpinfoheader[7] = (unsigned char)(bmp->width >> 24);
    bmpinfoheader[8] = (unsigned char)(bmp->height);
    bmpinfoheader[9] = (unsigned char)(bmp->height >> 8);
    bmpinfoheader[10] = (unsigned char)(bmp->height >> 16);
    bmpinfoheader[11] = (unsigned char)(bmp->height >> 24);

    f = fopen(filename, "wb");
    fwrite(bmpfileheader, 1, 14, f);
    fwrite(bmpinfoheader, 1, 40, f);

    for (int i = 0; i < bmp->height; i++) {
        fwrite(bmp->pixels + (bmp->width * (bmp->height - i - 1)), 3, bmp->width, f);
    }
    fclose(f);
}

void draw_pie_segment(Bitmap *bmp, double start_angle, double end_angle, Pixel color) {
    for (int y = 0; y < bmp->height; y++) {
        for (int x = 0; x < bmp->width; x++) {
            int dx = x - CENTER_X;
            int dy = y - CENTER_Y;
            double distance = sqrt(dx * dx + dy * dy);
            if (distance <= RADIUS) {
                double angle = -atan2(dy, dx) * 180 / M_PI - 90;
                if (angle < 0) angle += 360;
                if (angle >= start_angle && angle <= end_angle) {
                    bmp->pixels[y * bmp->width + x] = color;
                }
            }
        }
    }
}

int main() {
    FILE *file;
    char *line;
    int score_count[10] = {0};

    line = (char *)malloc(MAX_LINE_LENGTH * sizeof(char));
    if (line == NULL) {
        perror("Error allocating memory");
        return EXIT_FAILURE;
    }

    file = fopen("input.html", "r");
    if (file == NULL) {
        perror("Error opening file");
        free(line);
        return EXIT_FAILURE;
    }

    // Find the line starting with "var resultList ="
    while (fgets(line, MAX_LINE_LENGTH, file) != NULL) {
        if (strncmp(line, "var resultList =", 16) == 0) {
            break;
        }
    }

    if (feof(file)) {
        fprintf(stderr, "Error: Line starting with 'var resultList =' not found\n");
        fclose(file);
        free(line);
        return EXIT_FAILURE;
    }

    // Find all occurrences of "SCORE":"N" where N is a one-digit number
    char *pos = line;
    while ((pos = strstr(pos, "\"SCORE\":\"")) != NULL) {
        pos += 9; // Move past "\"SCORE\":\""
        if (isdigit(*pos)) {
            int score = *pos - '0';
            if (score >= 0 && score <= 9) {
                score_count[score]++;
            }
        }
        pos++;
    }

    fclose(file);
    free(line);

    // Create a bitmap for the pie chart
    Bitmap bmp;
    bmp.width = WIDTH;
    bmp.height = HEIGHT;
    bmp.pixels = (Pixel *)malloc(WIDTH * HEIGHT * sizeof(Pixel));
    if (bmp.pixels == NULL) {
        perror("Error allocating memory for bitmap");
        return EXIT_FAILURE;
    }

    // Fill the bitmap with white color
    for (int i = 0; i < WIDTH * HEIGHT; i++) {
        bmp.pixels[i].r = 255;
        bmp.pixels[i].g = 255;
        bmp.pixels[i].b = 255;
    }

    // Colors for the pie segments
    Pixel colors[10] = {
        {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0},
        {0, 255, 255}, {255, 0, 255}, {128, 0, 0}, {0, 128, 0},
        {0, 0, 128}, {128, 128, 0}
    };

    // Calculate total scores
    int total_scores = 0;
    for (int i = 0; i <= 9; i++) {
        total_scores += score_count[i];
    }

    // Draw the pie chart segments
    double start_angle = 0.0;
    for (int i = 0; i <= 9; i++) {
        if (score_count[i] > 0) {
            double end_angle = start_angle + (score_count[i] / (double)total_scores) * 360.0;
            draw_pie_segment(&bmp, start_angle, end_angle, colors[i]);
            start_angle = end_angle;
        }
    }

    // Save the bitmap to a file
    save_bmp("pie_chart.bmp", &bmp);

    // Free allocated memory
    free(bmp.pixels);

    // Output the count of each score
    for (int i = 0; i <= 9; i++) {
        printf("SCORE %d: %d\n", i, score_count[i]);
    }

    return EXIT_SUCCESS;
}
```

:::

現在的程式碼確實可以產生正確的 BMP 了，接著我們將 CLI 的範例給它，讓它實作出相同的輸出與輸入格式，並完成 curl 抓取資料的部分：

> Great. Then try to make this interface:
> $ ./fin02 --help
> Usage: fin02 date
> -h, --help Display this information and exit.
> $ ./fin02 2024-04-23
> 0: 1183 (44.34%)
> 1: 612 (22.94%)
> 2: 386 (14.47%)
> 3: 238 (8.92%)
> 4: 109 (4.09%)
> 5: 53 (1.99%)
> 6: 42 (1.57%)
> 7: 45 (1.69%)
> $ ls
> output.bmp
>
> By using libcurl to fetch the data from https://cpe.cse.nsysu.edu.tw/cpe/scoreboard/<date>

:::spoiler Code 7

```c=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <curl/curl.h>

#define MAX_LINE_LENGTH 8 * 1024 * 1024 // 8MB
#define WIDTH 800
#define HEIGHT 800
#define CENTER_X (WIDTH / 2)
#define CENTER_Y (HEIGHT / 2)
#define RADIUS (WIDTH / 3)

typedef struct {
    unsigned char b;
    unsigned char g;
    unsigned char r;
} Pixel;

typedef struct {
    unsigned int width;
    unsigned int height;
    Pixel *pixels;
} Bitmap;

typedef struct {
    char *data;
    size_t size;
} MemoryBlock;

void save_bmp(const char *filename, Bitmap *bmp) {
    FILE *f;
    unsigned char bmpfileheader[14] = {
        'B', 'M',           // BMP signature
        0, 0, 0, 0,         // File size
        0, 0,               // Reserved
        0, 0,               // Reserved
        54, 0, 0, 0         // Data offset
    };
    unsigned char bmpinfoheader[40] = {
        40, 0, 0, 0,        // Info header size
        0, 0, 0, 0,         // Width
        0, 0, 0, 0,         // Height
        1, 0,               // Planes
        24, 0,              // Bits per pixel
        0, 0, 0, 0,         // Compression
        0, 0, 0, 0,         // Image size (can be 0 for BI_RGB)
        0, 0, 0, 0,         // X pixels per meter
        0, 0, 0, 0,         // Y pixels per meter
        0, 0, 0, 0,         // Total colors
        0, 0, 0, 0          // Important colors
    };

    unsigned int filesize = 54 + 3 * bmp->width * bmp->height;
    bmpfileheader[2] = (unsigned char)(filesize);
    bmpfileheader[3] = (unsigned char)(filesize >> 8);
    bmpfileheader[4] = (unsigned char)(filesize >> 16);
    bmpfileheader[5] = (unsigned char)(filesize >> 24);

    bmpinfoheader[4] = (unsigned char)(bmp->width);
    bmpinfoheader[5] = (unsigned char)(bmp->width >> 8);
    bmpinfoheader[6] = (unsigned char)(bmp->width >> 16);
    bmpinfoheader[7] = (unsigned char)(bmp->width >> 24);
    bmpinfoheader[8] = (unsigned char)(bmp->height);
    bmpinfoheader[9] = (unsigned char)(bmp->height >> 8);
    bmpinfoheader[10] = (unsigned char)(bmp->height >> 16);
    bmpinfoheader[11] = (unsigned char)(bmp->height >> 24);

    f = fopen(filename, "wb");
    fwrite(bmpfileheader, 1, 14, f);
    fwrite(bmpinfoheader, 1, 40, f);

    for (int i = 0; i < bmp->height; i++) {
        fwrite(bmp->pixels + (bmp->width * (bmp->height - i - 1)), 3, bmp->width, f);
    }
    fclose(f);
}

void draw_pie_segment(Bitmap *bmp, double start_angle, double end_angle, Pixel color) {
    for (int y = 0; y < bmp->height; y++) {
        for (int x = 0; x < bmp->width; x++) {
            int dx = x - CENTER_X;
            int dy = y - CENTER_Y;
            double distance = sqrt(dx * dx + dy * dy);
            if (distance <= RADIUS) {
                double angle = -atan2(dy, dx) * 180 / M_PI - 90;
                if (angle < 0) angle += 360;
                if (angle >= start_angle && angle <= end_angle) {
                    bmp->pixels[y * bmp->width + x] = color;
                }
            }
        }
    }
}

size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t realsize = size * nmemb;
    MemoryBlock *mem = (MemoryBlock *)userp;

    char *ptr = realloc(mem->data, mem->size + realsize + 1);
    if(ptr == NULL) {
        // out of memory
        return 0;
    }

    mem->data = ptr;
    memcpy(&(mem->data[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->data[mem->size] = 0;

    return realsize;
}

int fetch_data(const char *url, MemoryBlock *mem) {
    CURL *curl_handle;
    CURLcode res;

    mem->data = malloc(1);  // will be grown as needed by realloc
    mem->size = 0;    // no data at this point

    curl_global_init(CURL_GLOBAL_ALL);

    curl_handle = curl_easy_init();

    curl_easy_setopt(curl_handle, CURLOPT_URL, url);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)mem);
    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");

    res = curl_easy_perform(curl_handle);

    if(res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        return 1;
    }

    curl_easy_cleanup(curl_handle);
    curl_global_cleanup();

    return 0;
}

void parse_and_count_scores(const char *data, int score_count[10]) {
    const char *pos = data;
    while ((pos = strstr(pos, "\"SCORE\":\"")) != NULL) {
        pos += 9; // Move past "\"SCORE\":\""
        if (isdigit(*pos)) {
            int score = *pos - '0';
            if (score >= 0 && score <= 9) {
                score_count[score]++;
            }
        }
        pos++;
    }
}

void print_usage() {
    printf("Usage: fin02 date\n");
    printf("-h, --help Display this information and exit.\n");
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        print_usage();
        return EXIT_FAILURE;
    }

    if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
        print_usage();
        return EXIT_SUCCESS;
    }

    char url[256];
    snprintf(url, sizeof(url), "https://cpe.cse.nsysu.edu.tw/cpe/scoreboard/%s", argv[1]);

    MemoryBlock mem;
    if (fetch_data(url, &mem) != 0) {
        fprintf(stderr, "Failed to fetch data from %s\n", url);
        return EXIT_FAILURE;
    }

    int score_count[10] = {0};
    parse_and_count_scores(mem.data, score_count);
    free(mem.data);

    // Calculate total scores
    int total_scores = 0;
    for (int i = 0; i <= 9; i++) {
        total_scores += score_count[i];
    }

    // Print the score counts and percentages
    for (int i = 0; i <= 9; i++) {
        if (total_scores > 0) {
            printf("%d: %d (%.2f%%)\n", i, score_count[i], (score_count[i] / (double)total_scores) * 100);
        } else {
            printf("%d: %d (0.00%%)\n", i, score_count[i]);
        }
    }

    // Create a bitmap for the pie chart
    Bitmap bmp;
    bmp.width = WIDTH;
    bmp.height = HEIGHT;
    bmp.pixels = (Pixel *)malloc(WIDTH * HEIGHT * sizeof(Pixel));
    if (bmp.pixels == NULL) {
        perror("Error allocating memory for bitmap");
        return EXIT_FAILURE;
    }

    // Fill the bitmap with white color
    for (int i = 0; i < WIDTH * HEIGHT; i++) {
        bmp.pixels[i].r = 255;
        bmp.pixels[i].g = 255;
        bmp.pixels[i].b = 255;
    }

    // Colors for the pie segments
    Pixel colors[10] = {
        {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0},
        {0, 255, 255}, {255, 0, 255}, {128, 0, 0}, {0, 128, 0},
        {0, 0, 128}, {128, 128, 0}
    };

    // Draw the pie chart segments
    double start_angle = 0.0;
    for (int i = 0; i <= 9; i++) {
        if (score_count[i] > 0) {
            double end_angle = start_angle + (score_count[i] / (double)total_scores) * 360.0;
            draw_pie_segment(&bmp, start_angle, end_angle, colors[i]);
            start_angle = end_angle;
        }
    }

    // Save the bitmap to a file
    save_bmp("output.bmp", &bmp);

    // Free allocated memory
    free(bmp.pixels);

    return EXIT_SUCCESS;
}
```

:::

至此，程式已經的大致完成。但我們可以發現其已經開始忘記一開始的一些資料處理方式，我們提供錯誤的輸入並提醒它：

> ./fin02 2024-04-23             
> 0: 2362 (44.27%)
> 1: 1228 (23.01%)
> 2: 772 (14.47%)
> 3: 476 (8.92%)
> 4: 218 (4.09%)
> 5: 106 (1.99%)
> 6: 84 (1.57%)
> 7: 90 (1.69%)
> 8: 0 (0.00%)
> 9: 0 (0.00%)
> 
> It looks like you are calculating the data twice, only the line starting with var resultList =. Also, don't count 8 and 9.

:::spoiler Code 8

```c=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <curl/curl.h>

#define MAX_LINE_LENGTH 8 * 1024 * 1024 // 8MB
#define WIDTH 800
#define HEIGHT 800
#define CENTER_X (WIDTH / 2)
#define CENTER_Y (HEIGHT / 2)
#define RADIUS (WIDTH / 3)

typedef struct {
    unsigned char b;
    unsigned char g;
    unsigned char r;
} Pixel;

typedef struct {
    unsigned int width;
    unsigned int height;
    Pixel *pixels;
} Bitmap;

typedef struct {
    char *data;
    size_t size;
} MemoryBlock;

void save_bmp(const char *filename, Bitmap *bmp) {
    FILE *f;
    unsigned char bmpfileheader[14] = {
        'B', 'M',           // BMP signature
        0, 0, 0, 0,         // File size
        0, 0,               // Reserved
        0, 0,               // Reserved
        54, 0, 0, 0         // Data offset
    };
    unsigned char bmpinfoheader[40] = {
        40, 0, 0, 0,        // Info header size
        0, 0, 0, 0,         // Width
        0, 0, 0, 0,         // Height
        1, 0,               // Planes
        24, 0,              // Bits per pixel
        0, 0, 0, 0,         // Compression
        0, 0, 0, 0,         // Image size (can be 0 for BI_RGB)
        0, 0, 0, 0,         // X pixels per meter
        0, 0, 0, 0,         // Y pixels per meter
        0, 0, 0, 0,         // Total colors
        0, 0, 0, 0          // Important colors
    };

    unsigned int filesize = 54 + 3 * bmp->width * bmp->height;
    bmpfileheader[2] = (unsigned char)(filesize);
    bmpfileheader[3] = (unsigned char)(filesize >> 8);
    bmpfileheader[4] = (unsigned char)(filesize >> 16);
    bmpfileheader[5] = (unsigned char)(filesize >> 24);

    bmpinfoheader[4] = (unsigned char)(bmp->width);
    bmpinfoheader[5] = (unsigned char)(bmp->width >> 8);
    bmpinfoheader[6] = (unsigned char)(bmp->width >> 16);
    bmpinfoheader[7] = (unsigned char)(bmp->width >> 24);
    bmpinfoheader[8] = (unsigned char)(bmp->height);
    bmpinfoheader[9] = (unsigned char)(bmp->height >> 8);
    bmpinfoheader[10] = (unsigned char)(bmp->height >> 16);
    bmpinfoheader[11] = (unsigned char)(bmp->height >> 24);

    f = fopen(filename, "wb");
    fwrite(bmpfileheader, 1, 14, f);
    fwrite(bmpinfoheader, 1, 40, f);

    for (int i = 0; i < bmp->height; i++) {
        fwrite(bmp->pixels + (bmp->width * (bmp->height - i - 1)), 3, bmp->width, f);
    }
    fclose(f);
}

void draw_pie_segment(Bitmap *bmp, double start_angle, double end_angle, Pixel color) {
    for (int y = 0; y < bmp->height; y++) {
        for (int x = 0; x < bmp->width; x++) {
            int dx = x - CENTER_X;
            int dy = y - CENTER_Y;
            double distance = sqrt(dx * dx + dy * dy);
            if (distance <= RADIUS) {
                double angle = -atan2(dy, dx) * 180 / M_PI - 90;
                if (angle < 0) angle += 360;
                if (angle >= start_angle && angle <= end_angle) {
                    bmp->pixels[y * bmp->width + x] = color;
                }
            }
        }
    }
}

size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t realsize = size * nmemb;
    MemoryBlock *mem = (MemoryBlock *)userp;

    char *ptr = realloc(mem->data, mem->size + realsize + 1);
    if(ptr == NULL) {
        // out of memory
        return 0;
    }

    mem->data = ptr;
    memcpy(&(mem->data[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->data[mem->size] = 0;

    return realsize;
}

int fetch_data(const char *url, MemoryBlock *mem) {
    CURL *curl_handle;
    CURLcode res;

    mem->data = malloc(1);  // will be grown as needed by realloc
    mem->size = 0;    // no data at this point

    curl_global_init(CURL_GLOBAL_ALL);

    curl_handle = curl_easy_init();

    curl_easy_setopt(curl_handle, CURLOPT_URL, url);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)mem);
    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");

    res = curl_easy_perform(curl_handle);

    if(res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        return 1;
    }

    curl_easy_cleanup(curl_handle);
    curl_global_cleanup();

    return 0;
}

void parse_and_count_scores(const char *data, int score_count[8]) {
    const char *pos = data;
    pos = strstr(pos, "var resultList =");
    if (pos == NULL) {
        fprintf(stderr, "Error: 'var resultList =' not found in data\n");
        return;
    }

    // Move to the next line
    pos = strchr(pos, '\n');
    if (pos == NULL) {
        return;
    }

    // Find all occurrences of "SCORE":"N" where N is a one-digit number (0-7)
    while ((pos = strstr(pos, "\"SCORE\":\"")) != NULL) {
        pos += 9; // Move past "\"SCORE\":\""
        if (isdigit(*pos)) {
            int score = *pos - '0';
            if (score >= 0 && score <= 7) {
                score_count[score]++;
            }
        }
        pos++;
    }
}

void print_usage() {
    printf("Usage: fin02 date\n");
    printf("-h, --help Display this information and exit.\n");
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        print_usage();
        return EXIT_FAILURE;
    }

    if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
        print_usage();
        return EXIT_SUCCESS;
    }

    char url[256];
    snprintf(url, sizeof(url), "https://cpe.cse.nsysu.edu.tw/cpe/scoreboard/%s", argv[1]);

    MemoryBlock mem;
    if (fetch_data(url, &mem) != 0) {
        fprintf(stderr, "Failed to fetch data from %s\n", url);
        return EXIT_FAILURE;
    }

    int score_count[8] = {0};
    parse_and_count_scores(mem.data, score_count);
    free(mem.data);

    // Calculate total scores
    int total_scores = 0;
    for (int i = 0; i <= 7; i++) {
        total_scores += score_count[i];
    }

    // Print the score counts and percentages
    for (int i = 0; i <= 7; i++) {
        if (total_scores > 0) {
            printf("%d: %d (%.2f%%)\n", i, score_count[i], (score_count[i] / (double)total_scores) * 100);
        } else {
            printf("%d: %d (0.00%%)\n", i, score_count[i]);
        }
    }

    // Create a bitmap for the pie chart
    Bitmap bmp;
    bmp.width = WIDTH;
    bmp.height = HEIGHT;
    bmp.pixels = (Pixel *)malloc(WIDTH * HEIGHT * sizeof(Pixel));
    if (bmp.pixels == NULL) {
        perror("Error allocating memory for bitmap");
        return EXIT_FAILURE;
    }

    // Fill the bitmap with white color
    for (int i = 0; i < WIDTH * HEIGHT; i++) {
        bmp.pixels[i].r = 255;
        bmp.pixels[i].g = 255;
        bmp.pixels[i].b = 255;
    }

    // Colors for the pie segments
    Pixel colors[8] = {
        {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0},
        {0, 255, 255}, {255, 0, 255}, {128, 0, 0}, {0, 128, 0}
    };

    // Draw the pie chart segments
    double start_angle = 0.0;
    for (int i = 0; i <= 7; i++) {
        if (score_count[i] > 0) {
            double end_angle = start_angle + (score_count[i] / (double)total_scores) * 360.0;
            draw_pie_segment(&bmp, start_angle, end_angle, colors[i]);
            start_angle = end_angle;
        }
    }

    // Save the bitmap to a file
    save_bmp("output.bmp", &bmp);

    // Free allocated memory
    free(bmp.pixels);

    return EXIT_SUCCESS;
}
```

:::

程式完成。

整個過程大概花了一小時完成，在圓餅圖修正上面花了一些時間重試。

可以發現需要人類對於程式碼與題目有一定認知才能提醒或指引 LLM 進行修正，其依然不能直接完成程式。
