# 程式設計專題
## 提問區
> 所以道路跟村莊要怎麼存,要找時間討論一下嗎
>
> 另外我有個想法:有要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;
}
```

:::
## 遊戲流程
### 回合流程
```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

對應遊戲規則
* 板塊類型應是對應到這六種內陸板塊

* 骰子點數,則是對應到板塊上放置的數字指示物

* 最後沙漠是沒有數字指示物,但會有盜賊

板塊這樣宣告
```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++;
}
}
}
```

```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號中午結束測試