# NewGuard 3/27 ``` #include <iostream> #include <string.h> using namespace std; #define initial_heat37 192 #define initial_heat28 128 #define initial_heat19 64 bool CmdCompare(const char* CmdToCmp); //直接比對command_title bool StrCompare(char* context, const char* Compare); //比對字串 void SubContxt(char* subArr, char* mainArr, short begin, char target); //從指定位置開始分割字串直到指定字元 short CheckWind(char* wind); // 查看場、局風 void GameReset(void); // 重置紀錄 void HeatProcess(short); void MuscleProcess(short, short); short MuscleHeat(short, short); short GetType(short title_id); // 取得花色 short GetDigit(short title_id); // 取得數字 short GetID(short title_id); // 取得同牌id short RemoveID(short tile_id); // 取得牌種 bool inRange(short a, short x ,short b); struct Gameinfo{ short PlayerID = 1, BWind = 1, SWind = 1, OpenAt = 1, Master = 1, Mcombo = 0; Gameinfo() {} }; short Hand[23] = {0}; // 手牌最多到22張[5槓(20)+2] short Hand_size = 0; // 手牌數 short Table[474] = {0}; // 記錄所有牌的狀況 <tile_id , status> (-x = player x 的棄牌, 0 = 未知, x = player x 的手牌) short Restsum[48] = {4}; // 記錄所有牌種剩餘數量(還有幾張未被棄出) short Drawtime[48][5]; // 手牌變更度紀錄 short Heat[40]; // 記錄數牌可能性 short muscle[40][5]; // 紀錄筋牌影響來源; short LastThrow = 0; // 最後一個棄牌 short LastPlayer = 0; // 上一個玩家 char command_title[20] = {0}; // 指令 char command_contxt[70] = {0}; // 指令參數 int main() { //initialize Gameinfo currentGame; GameReset(); while (true) { memset(command_title, 0, 20 * sizeof(char)); //sting.h 僅用 memset memset(command_contxt, 0, 70 * sizeof(char)); command_title[0] = ' ', command_contxt[0] = ' '; char inputchar; bool is_title = true; for (short title_size = 0, contxt_size = 0; title_size < 20 && contxt_size < 70;) { inputchar = cin.get(); //輸入形式必須為 "<command> <context>[Enter]" if (inputchar == '\n') { command_title[title_size] = 0; command_contxt[contxt_size] = 0; break; } if (!is_title) { command_contxt[contxt_size++] = inputchar; continue; } else if (is_title && inputchar == ' ') { is_title = false; continue; } else command_title[title_size++] = inputchar; } cout << "Recieved: [" << command_title << ' ' << command_contxt << ']' << endl; //////////////////////////////////////////////////////////////////////////// // 開始(input) switch (command_title[1]) //first letter from command { case 's': //start currentGame.PlayerID = (short)command_contxt[3] - '0'; GameReset(); break; // 本局資訊(input) case 'i': //init { if (CmdCompare("/initGame")) { char subtxt[6] = {0}; SubContxt(subtxt, command_contxt, 0, ' '); currentGame.BWind = CheckWind(subtxt); SubContxt(subtxt, command_contxt, 0, ' '); currentGame.SWind = CheckWind(subtxt); currentGame.OpenAt = command_contxt[0] - '0'; currentGame.Master = command_contxt[2] - '0'; currentGame.Mcombo = command_contxt[4] - '0'; } // 發牌(input) else if (CmdCompare("/initCard")) { char subtxt[4] = {0}; //if莊家 17張手牌, else 16張手牌 if(currentGame.PlayerID == currentGame.Master) Hand_size = 17; else Hand_size = 16; for(short i = 0; i < Hand_size; i++) { SubContxt(subtxt, command_contxt, 0, ' '); short tile_ini = (subtxt[0] - '0') * 100 + (subtxt[1] - '0') * 10 + (subtxt[2] - '0'); Hand[i] = tile_ini; Table[tile_ini] = currentGame.PlayerID; } } break; } // 摸(input) case 'm': //mo { short tile_mo = (command_contxt[0] - '0') * 100 + (command_contxt[1] - '0') * 10 + (command_contxt[2] - '0'); Table[tile_mo] = currentGame.PlayerID; Hand[Hand_size++] = tile_mo; break; } // 詢問AI動作(input) case 'a': //ask { //cout << "test ask\n"; // throw丟(output) if (command_contxt[0] == 't') { if (LastThrow != 0) // 上回合沒有吃碰槓(時間處理) { for (short p = 1; p <= 4; p++) if (p != currentGame.PlayerID && p != LastPlayer) Drawtime[RemoveID(LastThrow)][p] = 0; } short subhand[23] = {0}; short subhand_size = Hand_size; for(short i = 0; i < Hand_size; i++) subhand[i] = Hand[i]; bool throwEnd = false, numeric = false; short tothrow = 0; //the tile to throw // time check & replicant count short reps[48] = {0}; //replicant count for (short i = 0; i < subhand_size; i++) { reps[RemoveID(subhand[i])]++; short t_sum = 0; for (short p = 1; p <= 4; p++) if (p != currentGame.PlayerID) { if (Drawtime[RemoveID(subhand[i])][p] != -1) t_sum += Drawtime[RemoveID(subhand[i])][p]; else { t_sum = -1; break; } } if (t_sum == 0) { if (!throwEnd) { tothrow = subhand[i]; throwEnd = true; //cout << "time check throw" << endl; } else if ( (GetType(subhand[i]) != 4 && GetType(tothrow) == 4) || // 數牌 > 字牌 (Restsum[RemoveID(subhand[i])] > Restsum[RemoveID(tothrow)]) ) // 剩張多 > 剩張少 { tothrow = subhand[i]; } } } // total sum (4 - restsum + replicants) of symbol = 4 short minsum = 6; if (!throwEnd) { for (short i = 0; i < subhand_size; i++) { if (GetType(subhand[i]) == 4) { short s = Restsum[RemoveID(subhand[i])] - reps[RemoveID(subhand[i])]; // cout << "s: " << s << endl; if (s == 0) { tothrow = subhand[i]; throwEnd = true; //cout << "total sum throw" << endl; break; } else if (s < minsum) { minsum = s; tothrow = subhand[i]; } } else numeric = true; } } //cout << "current throw: " << tothrow << endl; // numeric calculation if (!throwEnd && numeric) { short endHeat = 0, minHeat = initial_heat37*3 + 1; short htothrow = 0; for (short i = 0; i < subhand_size; i++) { if (GetType(subhand[i]) == 4) continue; //cout << "(num)current tile: " << subhand[i]; endHeat = 0; for (short p = 1; p <= 4; p++) if (p != currentGame.PlayerID) endHeat += (Drawtime[subhand[i]][p] == 0 && muscle[RemoveID(subhand[i])][p] != 0)? //只有最後一張棄牌才納入筋牌計算 MuscleHeat(subhand[i], p) : Heat[RemoveID(subhand[i])]; //cout << " endHeat = " << endHeat << " v " << minHeat << endl; // +time calc if (endHeat < minHeat) { minHeat = endHeat; htothrow = subhand[i]; } } //cout << "htothrow: " << htothrow << endl; if (minsum > Restsum[RemoveID(htothrow)] +1) tothrow = htothrow; } else throwEnd = true; cout << "/throw " << tothrow << endl << flush; if (GetType(tothrow) != 4) HeatProcess(tothrow); Restsum[RemoveID(tothrow)]--; LastThrow = tothrow; short temp; for (temp = 0; temp < Hand_size; temp++) if (Hand[temp] == tothrow) break; if(temp != Hand_size) { Table[Hand[temp]] = currentGame.PlayerID * -1; Hand[temp] = Hand[Hand_size-1]; Hand[--Hand_size] = 0; } } // eat吃(output) else if (command_contxt[0] == 'e') { cout << "/pass" << endl; } // pong碰(output) else if (command_contxt[0] == 'p') { cout << "/pass" << endl; } // gong槓(output) else if (command_contxt[0] == 'g') { cout << "/pass" << endl; } // hu胡(output) else if (command_contxt[0] == 'h') { cout << "/hu" << endl; } break; } //棄牌(input) case 't': //throw { short playerID = command_contxt[0] - '0'; short tile_id = (command_contxt[2] - '0') * 100 + (command_contxt[3] - '0') * 10 + (command_contxt[4] - '0'); if (playerID == currentGame.PlayerID) { if(Table[tile_id] == currentGame.PlayerID) { if (LastThrow != 0) // 上回合沒有吃碰槓(時間處理) { for (short p = 1; p <= 4; p++) if (p != currentGame.PlayerID && p != LastPlayer) Drawtime[RemoveID(LastThrow)][p] = 0; } Restsum[RemoveID(tile_id)]--; short temp; for (temp = 0; temp < Hand_size; temp++) if (Hand[temp] == tile_id) break; if(temp != Hand_size) { Table[Hand[temp]] = currentGame.PlayerID * -1; Hand[temp] = Hand[Hand_size-1]; Hand[--Hand_size] = 0; } } } else { if (LastThrow != 0) // 上回合沒有吃碰槓(時間處理) { for (short p = 1; p <= 4; p++) if (p != currentGame.PlayerID && p != LastPlayer) Drawtime[RemoveID(LastThrow)][p] = 0; // drawtime++ for (short i = 11; i <= 47; i++) if (Drawtime[i][playerID] != -1) Drawtime[i][playerID]++; } Drawtime[RemoveID(tile_id)][playerID] = 0; //棄牌家時間歸零 LastThrow = tile_id; if (GetType(tile_id) != 4) { HeatProcess(tile_id); MuscleProcess(tile_id, playerID); } Table[tile_id] = playerID * -1; Restsum[RemoveID(tile_id)]--; } LastPlayer = playerID; break; } // 吃 case 'e': { char subtxt[3] = {0}; SubContxt(subtxt, command_contxt, 0, ' '); short playerID = subtxt[0] - '0'; short tile_id; if (playerID == currentGame.PlayerID) for (short i = 0; i < 3; i++) { SubContxt(subtxt, command_contxt, 0, ' '); tile_id = (subtxt[0] - '0') * 100 + (subtxt[1] - '0') * 10 + (subtxt[2] - '0'); short temp; for (temp = 0; temp < Hand_size; temp++) if (Hand[temp] == tile_id) break; if(temp != Hand_size) { Table[Hand[temp]] = currentGame.PlayerID * -1; Hand[temp] = Hand[Hand_size-1]; Hand[--Hand_size] = 0; } } for (short i = 0; i < 3; i++) { SubContxt(subtxt, command_contxt, 0, ' '); tile_id = (subtxt[0] - '0') * 100 + (subtxt[1] - '0') * 10 + (subtxt[2] - '0'); if(tile_id == LastThrow) continue; Table[tile_id] = playerID; if (GetType(tile_id) != 4) HeatProcess(tile_id); Restsum[RemoveID(tile_id)]--; } // drawtime 0 for(short p = 1; p <= 4; p++) { if (p != currentGame.PlayerID && p != LastPlayer) Drawtime[RemoveID(LastThrow)][p] = 0; } LastThrow = 0; break; } // 碰 case 'p': { char subtxt[3] = {0}; SubContxt(subtxt, command_contxt, 0, ' '); short playerID = subtxt[0] - '0'; short tile_id; if (playerID == currentGame.PlayerID) for (short i = 0; i < 3; i++) { SubContxt(subtxt, command_contxt, 0, ' '); tile_id = (subtxt[0] - '0') * 100 + (subtxt[1] - '0') * 10 + (subtxt[2] - '0'); short temp; for (temp = 0; temp < Hand_size; temp++) if (Hand[temp] == tile_id) break; if(temp != Hand_size) { Table[Hand[temp]] = currentGame.PlayerID * -1; Hand[temp] = Hand[Hand_size-1]; Hand[--Hand_size] = 0; } } for (short i = 0; i < 3; i++) { SubContxt(subtxt, command_contxt, 0, ' '); tile_id = (subtxt[0] - '0') * 100 + (subtxt[1] - '0') * 10 + (subtxt[2] - '0'); if(tile_id == LastThrow) continue; Table[tile_id] = playerID; if (GetType(tile_id) != 4) HeatProcess(tile_id); Restsum[RemoveID(tile_id)]--; } LastThrow = 0; break; } // 槓 case 'g': { char subtxt[3] = {0}; SubContxt(subtxt, command_contxt, 0, ' '); short playerID = subtxt[0] - '0'; SubContxt(subtxt, command_contxt, 0, ' '); short Gtype = subtxt[0] - '0'; short tile_id; if (playerID == currentGame.PlayerID) { for (short i = 0; i < (Gtype != 1)? 4 : 1; i++) { SubContxt(subtxt, command_contxt, 0, ' '); tile_id = (subtxt[0] - '0') * 100 + (subtxt[1] - '0') * 10 + (subtxt[2] - '0'); short temp; for (temp = 0; temp < Hand_size; temp++) if (Hand[temp] == tile_id) break; if(temp != Hand_size) { Table[Hand[temp]] = currentGame.PlayerID * -1; Hand[temp] = Hand[Hand_size-1]; Hand[--Hand_size] = 0; } } } // drawtime++ if(playerID != currentGame.PlayerID) for (short i = 11; i <= 47; i++) if (Drawtime[i][playerID] != -1) Drawtime[i][playerID]++; if (Gtype == 0) break; //若為暗槓則跳過 if (Gtype != 1) // 明槓 for (short i = 0; i < 4; i++) { SubContxt(subtxt, command_contxt, 0, ' '); tile_id = (subtxt[0] - '0') * 100 + (subtxt[1] - '0') * 10 + (subtxt[2] - '0'); if(tile_id == LastThrow) continue; Table[tile_id] = playerID; if (GetType(tile_id) != 4) HeatProcess(tile_id); } else // 加槓 { SubContxt(subtxt, command_contxt, 0, ' '); tile_id = (subtxt[0] - '0') * 100 + (subtxt[1] - '0') * 10 + (subtxt[2] - '0'); Table[tile_id] = playerID; if (GetType(tile_id) != 4) HeatProcess(tile_id); } Restsum[RemoveID(tile_id)] = 0; LastThrow = 0; break; } // 確認AI有連接 case 'r': //ready cout << "/ready" << endl; break; // 有人胡牌 case 'h': //hu break; // 程式結束(input) case 'q': //quit return 0; // Other(input) default: if (CmdCompare("*/print")) { } else cout << "Unknown Command!" << endl; break; } //end of switch } //end of while true return -1; } bool CmdCompare(const char* CmdToCmp) { bool flag = true; short i; for (i = 0; CmdToCmp[i] != 0; i++) { if(command_title[i] != CmdToCmp[i] || i > 20 || command_title[i] == 0) { flag = false; break; } } return flag; } bool StrCompare(char* context, const char* Compare) //compare maximum 20 characters { bool flag = true; short i; for (i = 0; Compare[i] != 0; i++) if(context[i] != Compare[i] || i > 20 || context[i] == 0) { flag = false; break; } return flag; } void SubContxt(char* subArr, char* mainArr, short begin, char target) { short i; for (i = begin; *(mainArr + i) != target && *(mainArr + i) != 0; i++) { //cout << *(mainArr + i); *(subArr + i) = *(mainArr + i); } for (short j = begin; *(mainArr + j) != 0; j++) { *(mainArr + j) = *(mainArr + j + i + 1); } } short CheckWind(char* wind) { switch (*wind) { case 'E': return 1; case 'S': return 2; case 'W': return 3; case 'N': return 4; default: return -1; } } void GameReset(void) { Hand_size = 0; for (short i = 0; i < 23; i++) Hand[i] = 0; for (short i = 11; i <= 47; i++) { if (i%10 != 0) // 跳過20 30 40 { Table[i*10 + 0] = 0; Table[i*10 + 1] = 0; Table[i*10 + 2] = 0; Table[i*10 + 3] = 0; Restsum[i] = 4; Drawtime[i][1] = -1; Drawtime[i][2] = -1; Drawtime[i][3] = -1; Drawtime[i][4] = -1; } } for (short i = 11; i <= 39; i++) { muscle[i][1] = 0; muscle[i][2] = 0; muscle[i][3] = 0; muscle[i][4] = 0; if (i%10 == 0) // 跳過20 30 40 continue; else if (inRange(3, i % 10, 7)) // 3 ~ 7 { Heat[i] = initial_heat37; } else if (inRange(2, i % 10, 8)) // 2 或 8 { Heat[i] = initial_heat28; } else // 1 或 9 { Heat[i] = initial_heat19; } } } void HeatProcess(short tile_id) { /*if (GetType(tile_id) == 4) cout << "Heat Error!" << endl;*/ short m2, m1, z0, p1, p2; m2 = RemoveID(tile_id) - 2; m1 = RemoveID(tile_id) - 1; z0 = RemoveID(tile_id); p1 = RemoveID(tile_id) + 1; p2 = RemoveID(tile_id) + 2; if (inRange(3, GetDigit(tile_id), 7)) { Heat[m2] -= Restsum[m2]*Restsum[m1]; Heat[m1] -= Restsum[m2]*Restsum[m1] + Restsum[m1]*Restsum[p1]; Heat[z0] -= Restsum[m2]*Restsum[m1] + Restsum[m1]*Restsum[p1] + Restsum[p1]*Restsum[p2]; Heat[p1] -= Restsum[m1]*Restsum[p1] + Restsum[p1]*Restsum[p2]; Heat[p2] -= Restsum[p1]*Restsum[p2]; } else if (GetDigit(tile_id) == 2) // 2 { Heat[m1] -= Restsum[m1]*Restsum[p1]; Heat[z0] -= Restsum[m1]*Restsum[p1] + Restsum[p1]*Restsum[p2]; Heat[p1] -= Restsum[m1]*Restsum[p1] + Restsum[p1]*Restsum[p2]; Heat[p2] -= Restsum[p1]*Restsum[p2]; } else if (GetDigit(tile_id) == 8) // 8 { Heat[m2] -= Restsum[m2]*Restsum[m1]; Heat[m1] -= Restsum[m1]*Restsum[p1] + Restsum[m2]*Restsum[m1]; Heat[z0] -= Restsum[m1]*Restsum[p1] + Restsum[m2]*Restsum[m1]; Heat[p1] -= Restsum[m1]*Restsum[p1]; } else if (GetDigit(tile_id) == 1)// 1 { Heat[z0] -= Restsum[p1]*Restsum[p2]; Heat[p1] -= Restsum[p1]*Restsum[p2]; Heat[p2] -= Restsum[p1]*Restsum[p2]; } else if (GetDigit(tile_id) == 9) // 9 { Heat[z0] -= Restsum[m2]*Restsum[m1]; Heat[m1] -= Restsum[m2]*Restsum[m1]; Heat[m2] -= Restsum[m2]*Restsum[m1]; } } void MuscleProcess(short tile_id, short playerID) { short m3 = RemoveID(tile_id) - 3; short p3 = RemoveID(tile_id) + 3; if (inRange(1, m3, 9)) muscle[m3][playerID] = GetDigit(tile_id); if (inRange(1, p3, 9)) muscle[p3][playerID] = GetDigit(tile_id); } short MuscleHeat(short tile_id, short playerID) { /*if (GetType(tile_id) == 4) cout << "MHeat Error!" << endl;*/ short m2, m1, z0, p1, p2; m2 = RemoveID(tile_id) - 2; m1 = RemoveID(tile_id) - 1; z0 = RemoveID(tile_id); p1 = RemoveID(tile_id) + 1; p2 = RemoveID(tile_id) + 2; short mheat = -1; //cout << muscle[z0][playerID] << " from " << tile_id << " " << playerID << endl; switch (muscle[z0][playerID]) { case 1: case 2: case 3: mheat += Restsum[m1]*Restsum[z0]*Restsum[p1]; mheat += Restsum[z0]*Restsum[p1]*Restsum[p2]; break; case 7: case 8: case 9: mheat += Restsum[m2]*Restsum[m1]*Restsum[z0]; mheat += Restsum[m1]*Restsum[z0]*Restsum[p1]; break; case 4: if (GetDigit(tile_id) == 1) mheat = 0; else { mheat += Restsum[m1]*Restsum[z0]*Restsum[p1]; mheat += Restsum[z0]*Restsum[p1]*Restsum[p2]; } break; case 5: mheat = Restsum[m1]*Restsum[z0]*Restsum[p1]; break; case 6: if (GetDigit(tile_id) == 9) mheat = 0; else { mheat += Restsum[m2]*Restsum[m1]*Restsum[z0]; mheat += Restsum[m1]*Restsum[z0]*Restsum[p1]; } break; default: //cout << "MHeat Error!" << endl; break; } return mheat; } short GetType(short tile_id) { // 如果title_id > 999, print warning /*if(tile_id > 999) cout << "[Warning] - The tile_id > 999.\n";*/ // return type return tile_id / 100; } short GetDigit(short tile_id) { // 如果title_id > 999, print warning /*if(tile_id > 999) cout << "[Warning] - The tile_id > 999.\n";*/ // return digit return (tile_id / 10) % 10; } short GetID(short tile_id) { // 如果title_id > 999, print warning /*if(tile_id > 999) cout << "[Warning] - The tile_id > 999.\n";*/ // return id return tile_id % 10; } short RemoveID(short tile_id) { return tile_id / 10; } bool inRange(short a, short x ,short b) { if (a <= x && x <= b) return true; return false; }