规则游戏中两个玩家在两块完全相同的棋盘(10x10方格)上进行,两个玩家分别在各自的棋盘上放置他们的舰艇,当然对手是看不见的。 每一个玩家都有5艘舰艇:一艘驱逐舰(2格),一艘潜艇(3格),一艘巡洋舰(3格),一艘战列舰(4格)和一艘航空母舰(5格)。 每艘舰艇都在棋盘上占据一定数量的格子,每艘舰艇既可以横着放,也可以竖着放,但任意两艘舰艇不能互相交叠。 游戏的玩法是双方轮流“轰炸”对方的舰艇,每次轰炸的结果是击中或未击中都会显示,如果击中,该玩家就可以继续攻击,直到击不中为止。 游戏的目标是赶在对手之前把他所有的舰艇都击沉。 代码说明 代码文件common.c 通用函数,打印信息
server.c 双方对战主函数。提供上次是否击中信息,轰炸
playera.c 玩家A舰艇部署和轰炸策略,需要自己修改,已给出例子
playerb.c 玩家B舰艇部署和轰炸策略,需要自己修改,已给出例子
舰艇说明舰艇采用宏定义 见[[common.h]]文件
D为驱逐舰,S为潜艇,C为巡洋舰,B为战列舰,A为航母
部署后可以打印查看,如:
1 2 3 4 5 6 7 8 9 10 DD~~~~~~~~ SSS~~~~~~~ CCC~~~~~~~ BBBB~~~~~~ AAAAA~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~
参与者可以任意选择玩家A或玩家B,分别修改playera.c和playerb.c的内容。需要修改的地方:
PlayerAName 或 PlayerBName 改为自己的名字。 DeploymentA 或 DeploymentB 对舰艇进行部署。 StrategyA 或 StrategyB 根据服务器提供的信息制定攻击策略,每次只能调用一次开火函数。 注意:player程序中只能使用server提供的ALastHitB、firetoA之类的函数,可以使用适当的数据结构记录历史的击中信息,但不能出现获取对方部署之类的函数,否则视为作弊,直接判负。
可以有两份策略,也可以使用完全相同的策略。
使用说明除了player文件其他文件都不用修改。
自己编写好player代码,将所有文件加入到一个VC工程中,编译运行即可 。
先在本地调试自己的策略,然后将playera.c和playerb.c上传到自己的文件夹中。
也可以查看其他人的代码,与其他人进行对战。但不要针对其他人的部署进行攻击,因为实际中是不能看到对方部署的,而且要与所有人进行对战,每个人的部署都会不同。
每隔一定时间我会写脚本自动抓取每组的代码进行相互对战,胜率最高组有一定奖励!!!
玩得愉快!后续变种:
舰艇不能接触 舰艇可对角线排放 未击沉舰艇每回合后可移动(移动距离与其剩余格数一致) 每个玩家都有一发特殊炮弹,可以击打2x2区域或1x4区域。 增加计时功能,策略时间超过一定值直接忽略。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 #include "player.h" #include "server.h" int initial = 0 ;int researchButton = 1 ;typedef struct Informations { int hitNum; int optionS; int optionH; int last_Hit_Index[2 ]; int found[10 ][10 ]; } Information; Battlefield PlayerA_BF; char * PlayerAName = "fanzheng" ;static int Weight[15 ][15 ];int DeploymentA () { for (int i = 0 ; i < M; i++) for (int j = 0 ; j < M; j++) { PlayerA_BF.area[i][j] = 1 ; } for (int i = 0 ; i < 15 ; i++) for (int j = 0 ; j < 15 ; j++) { Weight[i][j] = 0 ; } PlayerA_BF.area[0 ][0 ] = D; PlayerA_BF.area[0 ][1 ] = D; PlayerA_BF.area[2 ][2 ] = S; PlayerA_BF.area[2 ][3 ] = S; PlayerA_BF.area[2 ][4 ] = S; PlayerA_BF.area[4 ][4 ] = C; PlayerA_BF.area[4 ][5 ] = C; PlayerA_BF.area[4 ][6 ] = C; PlayerA_BF.area[6 ][5 ] = B; PlayerA_BF.area[6 ][6 ] = B; PlayerA_BF.area[6 ][7 ] = B; PlayerA_BF.area[6 ][8 ] = B; PlayerA_BF.area[8 ][2 ] = A; PlayerA_BF.area[8 ][3 ] = A; PlayerA_BF.area[8 ][4 ] = A; PlayerA_BF.area[8 ][5 ] = A; PlayerA_BF.area[8 ][6 ] = A; printBF (&PlayerA_BF); return 0 ; } int * getAttack_Object_Index () { int * attack; return attack; } static int lasti = 0 ;static int lastj = 0 ;static int Weight[15 ][15 ];static int flag = 0 ;int StrategyA () { int i = 0 , j = 0 , max; int isHit = ALastHitB (); if (flag != 0 ) { Weight[lasti][lastj] -= 10000 ; if (isHit == 1 ) { if (lasti + 1 < 10 ) Weight[lasti + 1 ][lastj] += 5 ; if (lasti - 1 >= 0 ) Weight[lasti - 1 ][lastj] += 5 ; if (lastj + 1 < 10 ) Weight[lasti][lastj + 1 ] += 5 ; if (lastj - 1 >= 0 ) Weight[lasti][lastj - 1 ] += 5 ; if (lasti + 2 < 10 ) Weight[lasti + 2 ][lastj] += 4 ; if (lasti - 2 >= 0 ) Weight[lasti - 2 ][lastj] += 4 ; if (lastj + 2 < 10 ) Weight[lasti][lastj + 2 ] += 4 ; if (lastj - 2 >= 0 ) Weight[lasti][lastj - 2 ] += 4 ; if (lasti + 3 < 10 ) Weight[lasti + 3 ][lastj] += 3 ; if (lasti - 3 >= 0 ) Weight[lasti - 3 ][lastj] += 3 ; if (lastj + 3 < 10 ) Weight[lasti][lastj + 3 ] += 3 ; if (lastj - 3 >= 0 ) Weight[lasti][lastj - 3 ] += 3 ; if (lasti + 4 < 10 ) Weight[lasti + 4 ][lastj] += 2 ; if (lasti - 4 >= 0 ) Weight[lasti - 4 ][lastj] += 2 ; if (lastj + 4 < 10 ) Weight[lasti][lastj + 4 ] += 2 ; if (lastj - 4 >= 0 ) Weight[lasti][lastj - 4 ] += 2 ; } else { Weight[lasti][lastj] -= 10000 ; if (lasti + 1 < 10 ) Weight[lasti + 1 ][lastj] -= 5 ; if (lasti - 1 >= 0 ) Weight[lasti - 1 ][lastj] -= 5 ; if (lastj + 1 < 10 ) Weight[lasti][lastj + 1 ] -= 5 ; if (lastj - 1 >= 0 ) Weight[lasti][lastj - 1 ] -= 5 ; if (lasti + 2 < 10 ) Weight[lasti + 2 ][lastj] -= 4 ; if (lasti - 2 >= 0 ) Weight[lasti - 2 ][lastj] -= 4 ; if (lastj + 2 < 10 ) Weight[lasti][lastj + 2 ] -= 4 ; if (lastj - 2 >= 0 ) Weight[lasti][lastj - 2 ] -= 4 ; if (lasti + 3 < 10 ) Weight[lasti + 3 ][lastj] -= 3 ; if (lasti - 3 >= 0 ) Weight[lasti - 3 ][lastj] -= 3 ; if (lastj + 3 < 10 ) Weight[lasti][lastj + 3 ] -= 3 ; if (lastj - 3 >= 0 ) Weight[lasti][lastj - 3 ] -= 3 ; if (lasti + 4 < 10 ) Weight[lasti + 4 ][lastj] -= 2 ; if (lasti - 4 >= 0 ) Weight[lasti - 4 ][lastj] -= 2 ; if (lastj + 4 < 10 ) Weight[lasti][lastj + 4 ] -= 2 ; if (lastj - 4 >= 0 ) Weight[lasti][lastj - 4 ] -= 2 ; } } for (int k = 0 ; k < 10 ; k++) { for (int l = 0 ; l < 10 ; l++) { if (k == 0 && l == 0 ) { max = Weight[k][l]; } if (Weight[k][l] > max) { max = Weight[k][l]; i = k; j = l; } } } firetoB (i, j); flag = 1 ; lasti = i; lastj = j; return 0 ; }
目前这个算法的缺点在于贪心的范围过广,很多时候没有意义。其实,每次打中之后都应该更关注于离集中点最近的区域,也即击中点的四周。如果某个击中点的四周都没有再次击中,就要考虑换位置了。
但是目前这个算法非常依赖于一次击中,然后再根据击中的区域逐步蔓延,可是这样的话,如果用户放的位置非常稀疏,这样可能会需要遍历整个数组才能找到所有炮弹。
目前最成功也最稳定的方法,贪心权值+破坏中心区域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 #include "player.h" #include "server.h" int initial = 0 ;int researchButton = 1 ;typedef struct Informations { int hitNum; int optionS; int optionH; int last_Hit_Index[2 ]; int found[10 ][10 ]; } Information; Battlefield PlayerA_BF; char * PlayerAName = "fanzheng" ;static int Weight[15 ][15 ];static int fanz_Step_Memory[15 ][15 ];int DeploymentA () { for (int i = 0 ; i < M; i++) for (int j = 0 ; j < M; j++) { PlayerA_BF.area[i][j] = 1 ; } for (int i = 0 ; i < 15 ; i++) for (int j = 0 ; j < 15 ; j++) { Weight[i][j] = 0 ; fanz_Step_Memory[i][j]=0 ; } for (int j=4 ;j>=0 ;j--){ Weight[4 -j][j]=3 ; } for (int j=9 ;j>=0 ;j--){ Weight[9 -j][j]=3 ; } for (int j=5 ;j<10 ;j++){ Weight[14 -j][j]=3 ; } PlayerA_BF.area[0 ][0 ] = D; PlayerA_BF.area[0 ][1 ] = D; PlayerA_BF.area[2 ][2 ] = S; PlayerA_BF.area[2 ][3 ] = S; PlayerA_BF.area[2 ][4 ] = S; PlayerA_BF.area[4 ][4 ] = C; PlayerA_BF.area[4 ][5 ] = C; PlayerA_BF.area[4 ][6 ] = C; PlayerA_BF.area[6 ][5 ] = B; PlayerA_BF.area[6 ][6 ] = B; PlayerA_BF.area[6 ][7 ] = B; PlayerA_BF.area[6 ][8 ] = B; PlayerA_BF.area[8 ][2 ] = A; PlayerA_BF.area[8 ][3 ] = A; PlayerA_BF.area[8 ][4 ] = A; PlayerA_BF.area[8 ][5 ] = A; PlayerA_BF.area[8 ][6 ] = A; printBF (&PlayerA_BF); return 0 ; } int * getAttack_Object_Index () { int * attack; return attack; } static int lasti = 0 ;static int lastj = 0 ;static int Weight[15 ][15 ];static int flag = 0 ;static int wrong_num=-10 ;int StrategyA () { int i = 0 , j = 0 , max; int isHit = ALastHitB (); if (flag != 0 ) { if (isHit == 1 ) { fanz_Step_Memory[lasti][lastj]=1 ; if ((lastj>0 &&fanz_Step_Memory[lasti][lastj-1 ]==1 )||(lastj<10 &&fanz_Step_Memory[lasti][lastj+1 ]==1 )){ wrong_num==2 ; int cur=lastj; while (cur>=0 ) { if (fanz_Step_Memory[lasti][cur]==0 )break ; cur--; } if (cur>=0 ) Weight[lasti][cur]+=10 ; cur=lastj; while (cur<10 ) { if (fanz_Step_Memory[lasti][cur]==0 ) break ; cur++; } if (cur<10 ) Weight[lasti][cur]+=10 ; } else if ((lasti>0 &&fanz_Step_Memory[lasti-1 ][lastj]==1 )||(lasti<10 &&fanz_Step_Memory[lasti+1 ][lastj]==1 )){ wrong_num=2 ; int cur=lasti; while (cur>=0 ) { if (fanz_Step_Memory[cur][lastj]==0 )break ; cur--; } if (cur>=0 ) Weight[cur][lastj]+=10 ; cur=lasti; while (cur<10 ) { if (fanz_Step_Memory[cur][lastj]==0 ) break ; cur++; } if (cur<10 ) Weight[cur][lastj]+=10 ; } else { if (lasti + 1 < 10 ) Weight[lasti + 1 ][lastj] += 5 ; if (lasti - 1 >= 0 ) Weight[lasti - 1 ][lastj] += 5 ; if (lastj + 1 < 10 ) Weight[lasti][lastj + 1 ] += 5 ; if (lastj - 1 >= 0 ) Weight[lasti][lastj - 1 ] += 5 ; } } else { fanz_Step_Memory[lasti][lastj]=-1 ; wrong_num--; if (lasti + 1 < 10 ) Weight[lasti + 1 ][lastj] -= 5 ; if (lasti - 1 >= 0 ) Weight[lasti - 1 ][lastj] -= 5 ; if (lastj + 1 < 10 ) Weight[lasti][lastj + 1 ] -= 5 ; if (lastj - 1 >= 0 ) Weight[lasti][lastj - 1 ] -= 5 ; } } if (wrong_num==0 ){ destoryCenter (); } max=-200 ; for (int k = 0 ; k < 10 ; k++) { for (int l = 0 ; l < 10 ; l++) { if (fanz_Step_Memory[k][l]==0 ){ if (Weight[k][l] > max) { max = Weight[k][l]; i = k; j = l; } } } } firetoB (i, j); flag = 1 ; lasti = i; lastj = j; return 0 ; } void destoryCenter () { for (int i=0 ;i<10 ;i++){ int start=0 ; for (;start<10 ;start++){ if (fanz_Step_Memory[i][start]==0 ){ int cur=start; while (cur<10 ) { if (fanz_Step_Memory[i][cur]!=0 ) break ; cur++; } Weight[i][(start+cur-1 )>>1 ]+=4 ; start=cur; } } } for (int i=0 ;i<10 ;i++){ int start=0 ; for (;start<10 ;start++){ if (fanz_Step_Memory[start][i]==0 ){ int cur=start; while (cur<10 ) { if (fanz_Step_Memory[cur][i]!=0 ) break ; cur++; } Weight[(start+cur-1 )>>1 ][i]+=4 ; start=cur; } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 PlayerA_BF.area[4 ][4 ] = D; PlayerA_BF.area[4 ][5 ] = D; PlayerA_BF.area[9 ][0 ] = S; PlayerA_BF.area[9 ][1 ] = S; PlayerA_BF.area[9 ][2 ] = S; PlayerA_BF.area[0 ][7 ] = C; PlayerA_BF.area[0 ][8 ] = C; PlayerA_BF.area[0 ][9 ] = C; PlayerA_BF.area[0 ][0 ] = B; PlayerA_BF.area[1 ][0 ] = B; PlayerA_BF.area[2 ][0 ] = B; PlayerA_BF.area[3 ][0 ] = B; PlayerA_BF.area[5 ][9 ] = A; PlayerA_BF.area[6 ][9 ] = A; PlayerA_BF.area[7 ][9 ] = A; PlayerA_BF.area[8 ][9 ] = A; PlayerA_BF.area[9 ][9 ] = A;