目錄表

國立屏東大學 資訊工程系 程式設計(一)

Turnin作業7


繳交方式說明

本次作業繳交將以資料夾的形式繳交,需要為每一題建立一個資料夾(資料夾名稱為該題題目前方之代號,第一題為「p1」,第二題為「p2」,餘以此類推),

繳交說明可參考作業3:連結

任何未依照正確繳交格式的檔案將以 0 分計算

本文使用「▴」及「↵」代表「空白字元」與「Enter 換行字元」,並且將使用者輸入的部份使用灰階方式顯示。 另外,題目的執行結果中,如果出現「(」、「)」、「:」、「;」、「.」與「,」等符號,皆為英文半形!


p1 動態字串輸入

在日常生活當中,我們使用者所接觸的交互式介面通常不會限制使用者輸入訊息的長度,比如我們跟朋友用 LINE 聊天時,想打多少字就想打多少,而不會被系統提示說我們只能在每一次輸入的訊息中,只能打15或20個字等限制的情況。

因此,本題需請同學完成一個C語言程式,讓使用者輸入一個 長度不限 的字串,並將使用者輸入的訊息重新顯示給使用者看。

實作注意

1. 同學在實作中可以嘗試先以 一個字元的方式 依序讀取輸入的內容,接著再檢查目前存放的空間是否已滿,如果滿了再將當前的空間增大。

2. 本次測試檔輸入的 內容長度 $\gt 1$

請參考以下 main.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "dynInput.h"

int main()
{
    unsigned curr_cap = 1;
    char* str = (char*)calloc(curr_cap, sizeof(char));

    printf("Enter a string: ");
    str = getInput(str, curr_cap);

    printf("You entered:\n[%s]\n", str);

    free(str);
    return 0;
}

在本題,同學需要實作以下函式:

待同學實作完畢後,請函式定義與實作分別放入以下檔案後並繳交:

本題將以下 Makefile 進行批改:

all: main.c dynInput.o
	gcc main.c dynInput.o
dynInput.o: dynInput.c
	gcc -c dynInput.c
clean:
	rm -rf *.*~ *~ a.* *.o *.o~

請參考以下輸出範例:

[3:23▴user@ws▴p1]▴./a.out↵
Enter▴a▴string:▴May▴the▴Force▴be▴with▴you.↵
You▴entered:↵
[May▴the▴Force▴be▴with▴you.]↵
[3:23▴user@ws▴p1]

[3:23▴user@ws▴p1]▴./a.out↵
Enter▴a▴string:▴It’s▴over,▴Anakin.▴I▴have▴the▴high▴ground.↵
You▴entered:↵
[It’s▴over,▴Anakin.▴I▴have▴the▴high▴ground.]↵
[3:23▴user@ws▴p1]

[3:23▴user@ws▴p1]▴./a.out↵
Enter▴a▴string:▴THE▴ROPE,▴ALONG▴WITH▴THE▴STICK,▴ARE▴TWO▴OF▴MANKINDS▴OLDEST▴TOOLS.▴THE▴STICK▴TO▴KEEP▴THE▴BAD▴AWAY.▴THE▴ROPE▴USED▴TO▴BRING▴THE▴GOOD▴TOWARD▴US.▴THEY▴WERE▴OUR▴FIRST▴FRIENDS,▴OF▴OUR▴OWN▴INVENTION.▴WHEREVER▴THERE▴WERE▴PEOPLE,▴THERE▴WERE▴THE▴ROPE▴AND▴THE▴STICK.▴-▴from▴Kobo▴Abe▴"Nawa"↵
You▴entered:↵
[THE▴ROPE,▴ALONG▴WITH▴THE▴STICK,▴ARE▴TWO▴OF▴MANKINDS▴OLDEST▴TOOLS.▴THE▴STICK▴TO▴KEEP▴THE▴BAD▴AWAY.▴THE▴ROPE▴USED▴TO▴BRING▴THE▴GOOD▴TOWARD▴US.▴THEY▴WERE▴OUR▴FIRST▴FRIENDS,▴OF▴OUR▴OWN▴INVENTION.▴WHEREVER▴THERE▴WERE▴PEOPLE,▴THERE▴WERE▴THE▴ROPE▴AND▴THE▴STICK.▴-▴from▴Kobo▴Abe▴"Nawa"]↵
[3:23▴user@ws▴p1]

  • 本題相關的程式碼路徑已註明於檔名右側,同學們可以透過路徑複製到自己的家目錄。
  • 本題將以上述提供的 Makefile 進行編譯,請同學作答時 “以題目提供的文件為主”
  • 本題應繳交檔案如下(main.cMakefile 則不需繳交):
    • dynInput.c
    • dynInput.h

p2 簡易泛型鍵值對管理器

本題需請同學完成一個簡易泛型鍵值對 (Key-Value) 的管理器。該程式在執行後會提供一個輸入介面,讓使用者可以輸入以下操作:

為了實現以上操作,本體提供 標頭檔 define.h 來幫助同學完成本次作業,請參考以下內容:

#define MIN_VSTRING_LEN 2
#define GROWTH_RATE 2
#define SHRINK_RATE 0.5

typedef enum
{
    INT,
    DOUBLE,
    STRING
} type_t;

typedef struct
{
    type_t  type;
    char    key[32];
    void*   value;
} kv_pair_t;

typedef struct
{
    kv_pair_t*  records;
    unsigned    size;
    unsigned    capacity;
} database;

在提供的標頭檔中,有以下兩個結構體:

從以上兩個結構體的內容可以看出本題所有操作都是建立在該兩個結構體上,因此本題需請同學完成以下函式:


在實作各項操作的函式時,請依照以下 左邊編號順序 進行錯誤判斷與處理(換行與排版請參考下方的輸出範例):

實作注意

  • 處理浮點數運算時,請以 double 型態處理。
  • 批改時:
    • 在輸入鍵值時,測試輸入 不小於 1 個字元
    • 在輸入資料的字串型態時,測試輸入 不小於 1 個字元

請參考下面 main.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "database.h"

void dbList(const database* db)
{
    printf("size(%u);cap(%u)\n", db->size, db->capacity);
    if (db->size < 1)
    {
        printf("no data\n");
        return;
    }

    for (unsigned i = 0; i < db->size; ++i)
    {
        printf("%u. ", i);
        dbPrint(&db->records[i]);
        printf("\n");
    }
}

void dbInit(database* db)
{
    db->records = (kv_pair_t*)malloc(2 * sizeof(kv_pair_t));
    db->size = 0;
    db->capacity = 2;
}

void dbHelp()
{
    printf("usage:\n");
    printf("  a)dd: add a new record\n");
    printf("  d)elete: delete an record\n");
    printf("  l)ist: list existing records\n");
    printf("  q)uit: exit the program\n");
}

int main()
{
    database db;
    char choice = 0;
    dbInit(&db);

    printf("[type 'h' for help]\n");
    do 
    {
        printf("> ");
        scanf(" %c", &choice);
        switch (choice)
        {
            case 'a':
                printf("\n");
                dbAdd(&db);
                printf("\n");
                break;
            case 'd':
                printf("\n");
                dbDelete(&db);
                printf("\n");
                break;
            case 'l':
                printf("\n");
                dbList(&db);
                printf("\n");
                break;
            case 'q':
                dbFree(&db);
                break;
            case 'h':
                printf("\n");
                dbHelp();
                printf("\n");
                break;
            default:
                printf("\n");
                printf("unknown choice\n");
                printf("\n");
        }
    } while (choice != 'q');

    dbFree(&db);

    return 0;
}

待同學實作完畢後以下函式後:

請函式定義與實作分別放入以下檔案後並繳交:

本題將以下面的 Makefile 進行批改:

all: main.c database.o
	gcc main.c database.o
database.o: database.c define.h
	gcc -c database.c
clean:
	rm -rf *.*~ *~ a.* *.o *.o~

本題範例輸出如下:

[3:23▴user@ws▴p2]▴./a.out↵
[type▴'h'▴for▴help]↵
>▴h↵

usage:↵
▴▴a)dd:▴add▴a▴new▴record↵
▴▴d)elete:▴delete▴an▴record↵
▴▴l)ist:▴list▴existing▴records↵
▴▴q)uit:▴exit▴the▴program↵

>▴D↵

unknown▴choice↵

>▴d↵

no▴data↵

>▴l↵

size(0);cap(2)↵
no▴data↵

>▴q↵
[3:23▴user@ws▴p2]

[3:23▴user@ws▴p2]▴./a.out↵
[type▴'h'▴for▴help]↵
>▴a↵

key:▴k▴1↵
invalid▴key↵

>▴a↵

key:▴k@1↵
invalid▴key↵

>▴a↵

key:▴k1↵
type▴(int,▴double,▴string):▴int↵
value:▴114514↵

>▴l↵

size(1);cap(2)↵
0.▴k1(int):▴[114514]↵

>▴a↵

key:▴k1↵
data▴already▴exists↵

>▴a↵

key:▴k2↵
type▴(int,▴double,▴string):▴float↵
unknown▴type↵

>▴a↵

key:▴k2↵
type▴(int,▴double,▴string):▴double↵
value:▴114514.114514↵

>▴a↵

key:▴k3↵
type▴(int,▴double,▴string):▴string↵
value:▴This▴is▴a▴test▴message▴that▴checks▴if▴dynamic▴input▴is▴working▴or▴not,▴if▴this▴message▴is▴not▴getting▴chopped▴off▴or▴displaying▴some▴visual▴errors,▴then▴IT▴WORKS▴:).↵

>▴l↵

size(3);cap(4)↵
0.▴k1(int):▴[114514]↵
1.▴k2(double):▴[114514.114514]↵
2.▴k3(string):▴[This▴is▴a▴test▴message▴that▴checks▴if▴dynamic▴input▴is▴working▴or▴not,▴if▴this▴message▴is▴not▴getting▴chopped▴off▴or▴displaying▴some▴visual▴errors,▴then▴IT▴WORKS▴:).]↵

>▴q↵
[3:23▴user@ws▴p2]

[3:23▴user@ws▴p2]▴./a.out↵
[type▴'h'▴for▴help]↵
>▴a↵

key:▴k1↵
type▴(int,▴double,▴string):▴int↵
value:▴114514↵

>▴a↵

key:▴k2↵
type▴(int,▴double,▴string):▴double↵
value:▴114514.114514↵

>▴a↵

key:▴k3↵
type▴(int,▴double,▴string):▴string↵
value:▴A▴test▴string▴that▴says▴“Hello▴World!”!↵

>▴l↵

size(3);cap(4)↵
0.▴k1(int):▴[114514]↵
1.▴k2(double):▴[114514.114514]↵
2.▴k3(string):▴[A▴test▴string▴that▴says▴“Hello▴World!”!]↵

>▴d↵

key:▴k▴1↵
data▴not▴found↵

>▴d↵

key:▴k2↵

>▴l↵

size(2);cap(2)↵
0.▴k1(int):▴[114514]↵
1.▴k3(string):▴[A▴test▴string▴that▴says▴“Hello▴World!”!]↵

>▴d↵

key:▴k1↵

>▴l↵

size(1);cap(1)↵
0.▴k3(string):▴[A▴test▴string▴that▴says▴“Hello▴World!”!]↵

>▴q↵
[3:23▴user@ws▴p2]

  • 本題相關的程式碼路徑已註明於檔名右側,同學們可以透過路徑複製到自己的家目錄。
  • 本題將以上述提供的 Makefile 進行編譯,請同學作答時 “以題目提供的文件為主”
  • 本題應繳交檔案如下(define.hmain.cMakefile 則不需繳交):
    • database.c
    • database.h

p3 五子棋-最佳落子位點判斷

經過了前幾週的作業對各種棋型(如活三死四等)的練習,同學已經具備了分析棋盤棋型的能力。本題為五子棋系列的綜合實踐題:將模擬真實比賽對弈環境,給定目前的棋盤狀態與落子顏色後, 請同學參考 五子棋 AI 程式競賽 - 進階篇權重分析的方法,找出棋盤上目前「最佳」的落子位置(最佳落子位置是由以下權重分析規則決定)。

權重分析規則:

  1. 活四 / 死四 / 洞四 / 洞死四:10000 分
    • 落子後能在該方向形成連五(直接獲勝)。
  2. 活三 / 洞三:1000 分
    • 落子後能形成「活四」的點。
  3. 死三 / 洞死三:800 分
    • 落子後能形成「死四」的點。
  4. 活二 / 洞二:100 分
    • 落子後能在該方向形成「活三」。
  5. 死二:80 分
    • 落子後能在該方向形成「死三」。
  6. 活一:10 分
  7. 死一:1 分
  • 常見錯誤:.1.1.1.棋型為死三而不是洞三。

可參考以下 main.c , define.h 的內容,讀取命令列參數與棋盤:

typedef enum {Black=49, White=48, None=0} Player;

#include <stdio.h>
#include <string.h>
#include "chess.h"

int main(int argc, char *argv[])
{
    char chessboard[19][19];
    Player player;

    for(int i=0; i<19; i++)
        for(int j=0; j<19; j++)
            scanf(" %c", &chessboard[i][j]);

    player = (strcmp(argv[1], "Black") == 0) ? Black : White;
		
    findBestMove(chessboard, player);
}

本題的執行結果可參考如下:

[3:23 user@ws p3] ./a.out Black < testfile_1.cb↵
J,▴11↵
[3:23 user@ws p3] ./a.out White < testfile_2.cb↵
P,▴▴8↵
[3:23 user@ws p3] ./a.out Black < testfile_3.cb↵
N,▴15↵
[3:23 user@ws p3]

本題測試檔路徑:

  • 建議參考前兩週作業所寫的五子棋作業。
  • argv[1] 為你本次程式執行所持的棋子,“Black” 為黑;“White” 為白。
  • 本題的所有測試檔案均經過設計,只會出現一組最高分的最佳落子點
  • 本題需使用提供的 main.c 來實作,不限制其他 Turnin 所繳交的檔名,但必須繳交 Makefile 檔案並將可執行檔命名為 a.out。
  • 本題批改時將採人工批改
  • 請勿使用AI撰寫,若是助教發現疑似使用AI撰寫,將會約談同學。
  • 約談過程中,若對本人繳交之代碼內容回答模糊、邏輯不通,將以 0 分計算。

p4 五子棋-第一次預賽

在上個禮拜作業7的第6題中,同學已經完成亂數版的五子棋並上傳至平台進行初步參賽,而這次功課需要請同學將上一題實作的內容修改至自己的參賽版本,讓自己的五子棋具有一定棋力。

同學修改完後,請將修改完的五子棋重新上傳至平台:國立屏東大學資工系電腦五子棋 AI 競賽平台上(同樣使用gomoku2026為turnin code)。預計將會於2026/05/28於舉行第一次預賽,所有參賽同學的作品將進行兩兩對奕比試10場,其中5場先手,5場後手,勝負記點採用:勝者2分、平手1分、敗者0分(每局獲勝規則為:黑子先行,五子連線為勝利)。預賽完成後依最終每位參賽同學所得到的分數給定此次作業配分:

  • 本題只要 上傳至參賽平台檢查是否能夠由平台順利完成編譯 即完成本題目,不需繳交至 turnin
  • 請勿過度使用AI撰寫,若是助教發現疑似使用AI撰寫,將會約談同學。
  • 約談過程中,若對本人繳交之代碼內容回答模糊、邏輯不通,將會取消同學分數,並以0分計。