---
# System prepended metadata

title: 程式設計專題

---

# 程式設計專題
## 提問區
> 所以道路跟村莊要怎麼存，要找時間討論一下嗎
> 
> 另外我有個想法：有要15~17找一天掛線上做專題嗎？邊做邊討論之類的
> (到14號前，我可能......能碰的時間有限，14號之後才可能完全動起來)
> 
> 又另一個想法：什麼時候要進入試玩階段
> 最晚或許17號就該定案+調整，18號(截止日)寫報告
>  [name=何躍陽]


## 地圖板塊
麥田x4、森林x4、草原x4、山脈x3、丘陵x3、沙漠x1


| 編號 | 板塊 | 數量 | 生產資源 |
|:----:|:----:|:----:|:--------:|
|  0   | 沙漠 |  1   |   N/A   |
|  1   | 麥田 |  4   |   小麥 grain   |
|  2   | 森林 |  4   |   木頭 lumber   |
|  3   | 草原 |  4   |   羊毛 wool   |
|  4   | 山脈 |  3   |   石頭 ore   |
|  5   | 丘陵 |  3   |   磚頭 brick   |

### 數字指示物
共 18 個，2與12各一個，3-6, 8-11各兩個。

### 板塊位置
由左至右，由上至下，共19塊
### 板塊 struct 設計

| 型別 | 變數名稱 |  中文解釋  |      值      |        解釋        |
|:----:|:--------:|:----------:|:------------:|:------------------:|
| int  |   type   |  板塊類型  |     0-5      |                    |
| int  |  point   |  骰子點數  | 0, 2-6, 8-12 |                    |
| int  |  robber  | 是否有盜賊 |     0,1      |                    |


## 需要那些結構
- 板塊
- 玩家
    :::spoiler:::
    ```c=
    enum {WHEAT = 1, WOOD, WOOL, STONE, BRICK};

    struct  _player {
        int32_t id;        // 可能不會用，應該會用player[3]的array處理
        int32_t resource[6]; // not show to other players
        int32_t total_resource; //show to other players
        int32_t Is_use_develop_card; // one round use once
        
        int32_t NPC_difficulty; // user are 0, only for NPC
    }__attribute__ ((__packed__));
    typedef struct _player Player;
    ```
    :::
- 道路
- 村莊
- 系統
    :::spoiler:::
    ```c=
    const int32_t WIN_SCORE = 10;
    struct  _system {
        int32_t player_num;     // 3 or 4
        int32_t knight_card;    // at most 14
        int32_t score_card;     // at most 5
        size_t bank_resource[6]; // all: 19, 19, 19, 19, 19. Can't be zero.
        
        int32_t longest_road;   // num of longest road in total players 
        int32_t lr_player;      // the player_id who has longest road card               
        int32_t max_knight;     // num of max knight card in total players 
        int32_t mk_player;      // the player_id who has max_num knight cards
        
        int32_t player_score[4];
    }__attribute__ ((__packed__));
    typedef struct _system System;
    ```
    :::


### 工作分配
- 陽：計分、電腦、地圖呈現, etc
- 蔡：板塊結構設計
- 江：遊戲機制、流程設計

:::spoiler **map**
```c=
#include <stdio.h>
#include <stdint.h>
#define MAP_WIDTH  5
#define MAP_HEIGHT 4

//////////////////
enum {DESERT, WHEAT_FIELD, FOREST, GRASSLAND, MOUNT, HILLS};
//////////////////

typedef struct {
    int type;     // 板塊類型（0~5）
    int point;    // 骰子點數（0, 2~6, 8~12）
    int robber;   // 是否有盜賊（0：無，1：有）
} Tile;



Tile gameMap[MAP_HEIGHT][MAP_WIDTH];   // 地圖板塊陣列

void initializeMap() {
    // 初始化地圖
    // 麥田板塊 x4
    gameMap[0][0].type = 1;    // 麥田
    gameMap[0][0].point = 5;
    gameMap[0][0].robber = 0;

    gameMap[0][1].type = 1;    // 麥田
    gameMap[0][1].point = 2;
    gameMap[0][1].robber = 0;

    gameMap[0][2].type = 1;    // 麥田
    gameMap[0][2].point = 10;
    gameMap[0][2].robber = 0;

    gameMap[0][3].type = 1;    // 麥田
    gameMap[0][3].point = 9;
    gameMap[0][3].robber = 0;

    // 森林板塊 x4
    gameMap[1][0].type = 2;    // 森林
    gameMap[1][0].point = 4;
    gameMap[1][0].robber = 0;

    gameMap[1][1].type = 2;    // 森林
    gameMap[1][1].point = 11;
    gameMap[1][1].robber = 0;

    gameMap[1][2].type = 2;    // 森林
    gameMap[1][2].point = 3;
    gameMap[1][2].robber = 0;

    gameMap[1][3].type = 2;    // 森林
    gameMap[1][3].point = 6;
    gameMap[1][3].robber = 0;

    // 草原板塊 x4
    gameMap[2][0].type = 3;    // 草原
    gameMap[2][0].point = 8;
    gameMap[2][0].robber = 0;

    gameMap[2][1].type = 3;    // 草原
    gameMap[2][1].point = 10;
    gameMap[2][1].robber = 0;

    gameMap[2][2].type = 3;    // 草原
    gameMap[2][2].point = 9;
    gameMap[2][2].robber = 0;

    gameMap[2][3].type = 3;    // 草原
    gameMap[2][3].point = 12;
    gameMap[2][3].robber = 0;

    // 山脈板塊 x3
    gameMap[3][0].type = 4;    // 山脈
    gameMap[3][0].point = 11;
    gameMap[3][0].robber = 0;

    gameMap[3][1].type = 4;    // 山脈
    gameMap[3][1].point = 4;
    gameMap[3][1].robber = 0;

    gameMap[3][2].type = 4;    // 山脈
    gameMap[3][2].point = 6;
    gameMap[3][2].robber = 0;

    // 丘陵板塊 x3
    gameMap[4][0].type = 5;    // 丘陵
    gameMap[4][0].point = 3;
    gameMap[4][0].robber = 0;

    gameMap[4][1].type = 5;    // 丘陵
    gameMap[4][1].point = 8;
    gameMap[4][1].robber = 0;

    gameMap[4][2].type = 5;    // 丘陵
    gameMap[4][2].point = 5;
    gameMap[4][2].robber = 0;

    // 沙漠板塊
    gameMap[5][0].type = 0;    // 沙漠
    gameMap[5][0].point = 0;
    gameMap[5][0].robber = 0;
}


void printMap() {
    char place[19][15] = { "山脈", "麥田", "麥田", "山脈", "森林", "山脈",
                            "草原", "麥田", "丘陵", "森林", "沙漠", "草原",
                            "丘陵", "草原", "丘陵", "麥田", "森林", "森林", "草原"};
    char num [56][3] = {0};
    for(int32_t i = 0; i < 56; i++){
        num[i][0] = (char)( (i+1)/10 + '0');
        num[i][1] = (char)( (i+1)%10 + '0');
    }

    printf("                                                                    \n");
    printf("                                                                    \n");
    printf("                    2:1   %s----%s   2:1                            \n", num[0], num[1]);
    printf("                  /    \\ /        \\ /    \\                       \n");
    printf("                 %s----%s   %s   %s----%s                           \n", num[2], num[3], place[0], num[4], num[5]);
    printf("                /        \\        /        \\                      \n");
    printf("  3:1 --%s----%s   %s   %s----%s   %s   %s----%s-- 3:1              \n", num[6], num[7], place[1], num[8], num[9], place[2], num[10], num[11]);
    printf("     \\ /        \\        /        \\        /        \\ /         \n");
    printf("      %s  %s   %s----%s   %s   %s----%s   %s   %s                    \n", num[12], place[3], num[13], num[14], place[4], num[15], num[16], place[5], num[17]);
    printf("       \\        /        \\        /        \\        /            \n");
    printf("        %s----%s   %s   %s----%s   %s   %s----%s                    \n", num[19], num[20], place[6], num[21], num[22], place[7], num[23], num[24]);
    printf("       /        \\        /        \\        /        \\            \n");
    printf("     %s   %s   %s----%s   %s   %s----%s   %s   %s                    \n", num[25], place[8], num[26], num[27], place[9], num[28], num[29], place[10], num[30]);
    printf("       \\        /        \\        /        \\        / \\         \n");
    printf("        %s----%s   %s   %s----%s   %s   %s----%s-- 2:1              \n", num[31], num[32], place[11], num[33], num[34], place[12], num[35], num[36]);
    printf("       /        \\        /        \\        /        \\            \n");
    printf("      %s  %s   %s----%s   %s   %s----%s   %s   %s                    \n", num[37], place[13], num[38], num[39], place[14], num[40], num[41], place[15], num[42]);
    printf("     / \\        /        \\        /        \\        /            \n");
    printf("   2:1 --%s----%s   %s   %s----%s   %s   %s----%s                    \n", num[43], num[44], place[16], num[45], num[46], place[17], num[48], num[49]);
    printf("              / \\        /        \\        / \\                   \n");
    printf("           2:1 --%s----%s   %s   %s----%s-- 3:1                     \n", num[50], num[51], place[18], num[52], num[53]);
    printf("                         \\        /                                \n");
    printf("                          %s----%s                                  \n", num[54], num[55]);
    printf("                           \\    /                                  \n");
    printf("                            3:1                                     \n");
    printf("                                                                    \n");
}

int main() {
    initializeMap();
    printMap();
    return 0;
}

:::
:::spoiler **print_map**
```c=
#include <stdio.h>

void print_map(char place[18][15], char num[56][3]){
    printf("                                                                    \n");
    printf("                                                                    \n");
    printf("                    2:1   %s----%s   2:1                            \n", num[0], num[1]);
    printf("                  /    \\ /        \\ /    \\                       \n");
    printf("                 %s----%s   %s   %s----%s                           \n", num[2], num[3], place[0], num[4], num[5]);
    printf("                /        \\        /        \\                      \n");
    printf("  3:1 --%s----%s   %s   %s----%s   %s   %s----%s-- 3:1              \n", num[6], num[7], place[1], num[8], num[9], place[2], num[10], num[11]);
    printf("     \\ /        \\        /        \\        /        \\ /         \n");
    printf("      %s  %s   %s----%s   %s   %s----%s   %s   %s                    \n", num[12], place[3], num[13], num[14], place[4], num[15], num[16], place[5], num[17]);
    printf("       \\        /        \\        /        \\        /            \n");
    printf("        %s----%s   %s   %s----%s   %s   %s----%s                    \n", num[19], num[20], place[6], num[21], num[22], place[7], num[23], num[24]);
    printf("       /        \\        /        \\        /        \\            \n");
    printf("     %s   %s   %s----%s   %s   %s----%s   %s   %s                    \n", num[25], place[8], num[26], num[27], place[9], num[28], num[29], place[10], num[30]);
    printf("       \\        /        \\        /        \\        / \\         \n");
    printf("        %s----%s   %s   %s----%s   %s   %s----%s-- 2:1              \n", num[31], num[32], place[11], num[33], num[34], place[12], num[35], num[36]);
    printf("       /        \\        /        \\        /        \\            \n");
    printf("      %s  %s   %s----%s   %s   %s----%s   %s   %s                    \n", num[37], place[13], num[38], num[39], place[14], num[40], num[41], place[15], num[42]);
    printf("     / \\        /        \\        /        \\        /            \n");
    printf("  2:1 --%s----%s   %s   %s----%s   %s   %s----%s                    \n", num[43], num[44], place[16], num[45], num[46], place[17], num[48], num[49]);
    printf("              / \\        /        \\        / \\                   \n");
    printf("           2:1 --%s----%s   %s   %s----%s-- 3:1                     \n", num[50], num[51], place[18], num[52], num[53]);
    printf("                         \\        /                                \n");
    printf("                          %s----%s                                  \n", num[54], num[55]);
    printf("                           \\    /                                  \n");
    printf("                            3:1                                     \n");
    printf("                                                                    \n");

}

int main(){
    char place[19][15] = { "山脈", "麥田", "麥田", "山脈", "森林", "山脈",
                            "草原", "麥田", "丘陵", "森林", "沙漠", "草原",
                            "丘陵", "草原", "丘陵", "麥田", "森林", "森林", "草原"};
    char num [56][3] = {0};
    for(int32_t i = 0; i < 56; i++){
        num[i][0] = (char)( (i+1)/10 + '0');
        num[i][1] = (char)( (i+1)%10 + '0');
    }

    print_map(place, num);

    return 0;
}
```
![](https://hackmd.io/_uploads/Hknrjz5Ph.png)

:::

## 遊戲流程
### 回合流程
```c=
int game_state;
// 0: 遊戲準備
// 1: 收成階段
// 2: 交易階段
// 3: 建築階段
// 4: 強盜（收成階段擲到七點時）
int current_player;
// 0 - 3 (玩家為0，其他為電腦玩家)
```


## 參考資料
[遊戲規則](https://andyventure.com/boardgame-catan/)
[遊戲規則-瘋桌遊](https://phantasiatw.pixnet.net/blog/post/117197942-%E5%8D%A1%E5%9D%A6%E5%B3%B6%E5%9F%BA%E6%9C%AC%E7%89%88-%E8%A6%8F%E5%89%87%2B%E5%BF%83%E5%BE%97)

## 板塊的structure
![](https://hackmd.io/_uploads/HJauC5aI2.png)

對應遊戲規則
* 板塊類型應是對應到這六種內陸板塊
![](https://hackmd.io/_uploads/Byp9Ac6L3.png)
* 骰子點數，則是對應到板塊上放置的數字指示物
![](https://hackmd.io/_uploads/SJxpRqp8h.png)
* 最後沙漠是沒有數字指示物，但會有盜賊
![](https://hackmd.io/_uploads/HyOwkopI2.png)

板塊這樣宣告
```c
enum ResourceType { // 宣告六種版塊類型
    Wheat = 0,
    Wood,
    Grassland,
    Mountain,
    Hill,
    Desert
};

struct CatanTile { // 定義每個版塊內容
    enum ResourceType resourceType; //類型
    int number;        // 分配到的數字指示物
    int hasRobber;     // 是否有盜賊
};

// 麥田x4、森林x4、草原x4、山脈x3、丘陵x3、沙漠x1
#define NUM_TILES 19  // 板塊的總數量

```

接下來我寫了一段可以隨機產生放置板塊順序的程式碼
```c
int main() {
    struct CatanTile tiles[NUM_TILES];

    generateCatanTiles(tiles);
    printCatanTiles(tiles);

    return 0;
}
```

```c
// 產生板塊
void generateCatanTiles(struct CatanTile* tiles) {
    // 內陸板塊有6種場地：麥田x4、森林x4、草原x4、山脈x3、丘陵x3、沙漠x1。
    enum ResourceType resources[NUM_TILES] = {
      Wheat, Wheat, Wheat, Wheat,
      Wood, Wood, Wood, Wood,
      Grassland, Grassland, Grassland, Grassland,
      Mountain, Mountain, Mountain,
      Hill, Hill, Hill,
      Desert };

    int numbers[NUM_TILES] = { 2, 3, 3, 4, 4, 5, 5, 6, 6, 8, 8, 9, 9, 10, 10, 11, 11, 12 };
    int remaining = NUM_TILES;

    shuffleResource(resources, NUM_TILES);  // 將resource洗牌
    shuffleNumbers(numbers, NUM_TILES - 1); // 將數字指示物洗牌

    int numberIdx = 0;
    for (int resourceIdx = 0; resourceIdx < NUM_TILES; resourceIdx++) {
        tiles[resourceIdx].resourceType = resources[resourceIdx];
        if (tiles[resourceIdx].resourceType == Desert) {
            // 是沙漠的話，不放數字，放盜賊
            tiles[resourceIdx].hasRobber = 1;
            tiles[resourceIdx].number = 0;
        } else {
            // 不是沙漠的話，放數字，不放盜賊
            tiles[resourceIdx].hasRobber = 0;
            tiles[resourceIdx].number = numbers[numberIdx];
            numberIdx++;
        }
    }
}
```

![數字指示物](https://hackmd.io/_uploads/H1zMGsaI2.png)

```c
// 測試函式：列印Catan板塊的資源類型和點數
void printCatanTiles(struct CatanTile* tiles) {
    int i;

    for (i = 0; i < NUM_TILES; i++) {
        printf("板塊 %d - 資源: ", i + 1);
        switch (tiles[i].resourceType) {
            case Wheat:
                printf("麥田");
                break;
            case Wood:
                printf("森林");
                break;
            case Grassland:
                printf("草原");
                break;
            case Mountain:
                printf("山脈");
                break;
            case Hill:
                printf("丘陵");
                break;
            case Desert:
                printf("沙漠");
                break;
            default:
              printf("%d", tiles[i].resourceType);
              break;
        }
        printf(", 數字: %d", tiles[i].number);
        if (tiles[i].hasRobber == 1) {
            printf(", 有盜賊");
        }
        printf("\n");
    }
}
```

下面是二個洗牌函式
```c
void shuffleResource(enum ResourceType* array, int length) {
    srand(time(NULL));
    
    for (int i = length - 1; i > 0; --i) {
        int j = rand() % (i + 1);
        enum ResourceType temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

void shuffleNumbers(int* array, int length) {
    srand(time(NULL));
    
    for (int i = length - 1; i > 0; --i) {
        int j = rand() % (i + 1);
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}
```

yangming3.14159@gmail.com
ryan6658@gmail.com

- 玩家的開局的村莊選擇
- 村莊建立判定
- 電腦玩家的交易 - 何
- 印出資訊   - 何
- 道路
    - 玩家有那裡道路 road[15][2] = {
        {1, 2}, 
        ....
    }
- 最長道路的計算 - (就是如果路徑中有其他玩家的村莊或城市，路徑會被切斷)這邊還沒判斷成功
- 遊戲流程(續) - 江
    - ~~港口交易~~ (完成)
    - ~~資源發放~~ (完成)
    - 道路建設
    - ~~搶奪資源~~ (完成)

17晚上完成
18號中午結束測試