# NewGuard.cpp 4/27 ``` #include <iostream> #include <cstdlib> #include <string.h> #include "Guard.h" using namespace std; #define initial_heat37 192 #define initial_heat28 128 #define initial_heat19 64 struct Gameinfo{ short PlayerID = 1, BWind = 1, SWind = 1, OpenAt = 1, Master = 1, Mcombo = 0; Gameinfo() {} }; Gameinfo currentGame; short Hand[23]; // 手牌最多到22張[5槓(20)+2] short Hand_size; // 手牌數 short Table[474]; // 記錄所有牌的狀況 <tile_id , status> (-x = player x 的棄牌, 0 = 未知, x = player x 的手牌) short Restsum[48]; // 記錄所有牌種剩餘數量(還有幾張未被棄出) short Drawtime[48][5]; // 手牌變更度紀錄 short Heat[40]; // 記錄數牌可能性 short muscle[40]; // 紀錄筋牌影響來源; short tothrow; short LastThrow = 0; // 最後一個棄牌 short LastPlayer = 0; // 上一個玩家 char command_title[20]; // 指令 char command_contxt[70]; // 指令參數 short Guard(void) { // 開始(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') { cout << "LastThrow = " << LastThrow << endl; 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; tothrow = 0; //the tile to throw // time check & replicant count short reps[48] = {0}; //replicant count short t_max[23]; arrClear(t_max, short(23), short(-1)); short t_sum[23]; arrClear(t_sum, short(23), short(-1)); for (short i = 0; i < subhand_size; i++) { reps[RemoveID(subhand[i])]++; for (short p = 1; p <= 4; p++) if (p != currentGame.PlayerID) { if (Drawtime[RemoveID(subhand[i])][p] > t_max[i]) t_max[i] == Drawtime[RemoveID(subhand[i])][p]; if (Drawtime[RemoveID(subhand[i])][p] > -1) t_sum[i] += Drawtime[RemoveID(subhand[i])][p]; } if (t_sum[i] != -1) t_sum[i]++; if (t_max[i] == 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) { //只有 T=0 才納入筋牌計算 endHeat += (GetType(LastThrow) == GetType(subhand[i]) && abs(GetDigit(LastThrow)-GetDigit(subhand[i])) == 3 && muscle[RemoveID(subhand[i])] != 0)? MuscleHeat(subhand[i], p) : Heat[RemoveID(subhand[i])]; // , cout << (GetType(LastThrow) == GetType(subhand[i])) << " " << // (abs(GetDigit(LastThrow)-GetDigit(subhand[i])) == 3) << " " << // muscle[RemoveID(subhand[i])] << endl; } // +time calc // if (t_max[i] != -1 && t_max[i] <= 3) // endHeat = endHeat * t_max[i] / 3; if (t_sum[i] != -1 && t_sum[i] <= 9) endHeat = endHeat * t_sum[i] / 9; // cout << Hand[i] << " endHeat = " << endHeat << " v " << minHeat << endl; if (endHeat < minHeat) { minHeat = endHeat; htothrow = subhand[i]; } } // cout << "htothrow: " << htothrow << endl; // cout << minsum << " vs " << Restsum[RemoveID(htothrow)] << endl; if (minsum > Restsum[RemoveID(htothrow)]) 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) { // change_output(tile_id); // cout << Restsum[RemoveID(tile_id)] << endl; 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; //cout << "Removed " << tile_id << " from Hand, Hand size = " << Hand_size << endl; } } 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; 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 (playerID == currentGame.PlayerID) { 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; } } 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; 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 (playerID == currentGame.PlayerID) { 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; } } 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}; short tile_id; SubContxt(subtxt, command_contxt, 0, ' '); short playerID = subtxt[0] - '0'; SubContxt(subtxt, command_contxt, 0, ' '); short Gtype = subtxt[0] - '0'; // drawtime++ if(playerID != currentGame.PlayerID) for (short i = 11; i <= 47; i++) if (Drawtime[i][playerID] != -1) Drawtime[i][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'); if (playerID == currentGame.PlayerID) { short temp; for (temp = 0; temp < Hand_size; temp++) if (Hand[temp] == tile_id) break; if(temp != Hand_size) { Table[Hand[temp]] = currentGame.PlayerID; Hand[temp] = Hand[Hand_size-1]; Hand[--Hand_size] = 0; } } if (tile_id == LastThrow || Gtype == 0) continue;//若為暗槓則跳過 Table[tile_id] = playerID; if (GetType(tile_id) != 4) HeatProcess(tile_id); } 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")) { cout << endl << "Hand size = " << Hand_size << endl; for (short i = 0; i < Hand_size; i++) { change_output(Hand[i]); cout << " "; cout << "剩張: " << Restsum[RemoveID(Hand[i])] << "\t"; if (GetType(Hand[i]) != 4) { cout << "Heat: "; cout.width(4); cout << Heat[RemoveID(Hand[i])]; } cout << endl; } } else if (CmdCompare("*/time")) { cout << endl << "Hand size = " << Hand_size << endl; for (short i = 0; i < Hand_size; i++) { change_output(Hand[i]); cout << " time: "; for (short p = 1; p <= 4; p++) cout << Drawtime[RemoveID(Hand[i])][p] << " "; cout << endl; } } else cout << "Unknown Command!" << endl; break; } //end of switch 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] = 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, GetDigit(m3), 9)) muscle[m3] = GetDigit(tile_id); if (inRange(1, GetDigit(p3), 9)) muscle[p3] = GetDigit(tile_id); // cout << m3 << " muscle: " << muscle[m3] << endl; // cout << p3 << " muscle: " << muscle[p3] << endl; } 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]) { 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; } void arrClear(short *Arraytoclear, short Arraysize, short Clearvalue = 0) { for (short i = 0; i < Arraysize; i++) Arraytoclear[i] = Clearvalue; } void change_output(short title_id) { if(GetType(title_id) == 1) cout << GetDigit(title_id) << "w "; else if(GetType(title_id) == 2) cout << GetDigit(title_id) << "t "; else if(GetType(title_id) == 3) cout << GetDigit(title_id) << "s "; else if(GetDigit(title_id) == 1) cout << "東"; else if(GetDigit(title_id) == 2) cout << "南"; else if(GetDigit(title_id) == 3) cout << "西"; else if(GetDigit(title_id) == 4) cout << "北"; else if(GetDigit(title_id) == 5) cout << "中"; else if(GetDigit(title_id) == 6) cout << "發"; else cout << "白"; } void InputMethod() { char inputchar; bool is_title = true; for (short title_size = 0, contxt_size = 0; title_size < 20 && contxt_size < 70;) { inputchar = cin.get(); 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; } }