为何跳出函数会导致Oware Abapa游戏棋盘数组异常?
Oware Abapa游戏保存后棋盘意外修改问题
我正在复刻Oware Abapa棋盘游戏,遇到一个问题:saveFile函数能正常将棋盘状态保存到文件,但保存流程结束后,游戏的pit数组(棋盘)被意外修改,原本应该保持原有状态不变。保存后程序还会自动从活跃玩家的最后一个坑位落子,我怀疑和break语句有关,但不确定原因,求解决。
棋盘展示函数
void show(int player, t_Pit p[], t_Pit s[], int win) { int a = player, o = !a; // 'a'ctive & 'o'pponent int x = a ? 0 : 6; int y = a ? 6 : 0; char *str = win ? "Wins the game\n\n" : "Select pit (1-6)\nSave board state (0): "; printf( "\n" "----+-----player%d-----+\n" "%2d |%2d|%2d|%2d|%2d|%2d|%2d|\n" "----+-----------------+\n" "%2d |%2d|%2d|%2d|%2d|%2d|%2d|\n" "----+-----player%d-----+\t" "\nPlayer %d %s", o, s[o], p[y+5], p[y+4], p[y+3], p[y+2], p[y+1], p[y+0], // NB: custom indexing s[a], p[x+0], p[x+1], p[x+2], p[x+3], p[x+4], p[x+5], a, a, str ); }
saveFile函数
void saveFile(int player, t_Pit p[], t_Pit s[]) { char fName[26]; printf("Input a name for the save file:"); scanf("%s", &fName); FILE *save = fopen(fName, "w"); if (save == NULL) { perror("Error opening file for writing"); return; } int a = player, o = !a; // 'a'ctive & 'o'pponent int x = a ? 0 : 6; int y = a ? 6 : 0; fprintf(save, "%2d\n" "%2d %2d %2d %2d %2d %2d\n" "%2d\n" "%2d %2d %2d %2d %2d %2d\n", s[o], p[y+5], p[y+4], p[y+3], p[y+2], p[y+1], p[y+0], s[a], p[x+0], p[x+1], p[x+2], p[x+3], p[x+4], p[x+5]); fclose(save); printf("file '%s' saved.", fName); }
main函数中相关逻辑
int main(void) { enum { nPlayer = 2, nOne = 6, nPit = (2*nOne), nSeed = 4, nWin = 25 }; // ease of code t_Pit score[ nPlayer ] = { 0 }; t_Pit pit[ nPit ] = { 0 }; int counter = 0; int counter1 = 0; int i; int actv = 0; for (int i = 0; i < nPit; ++i) { pit[i] = nSeed; } for ( ; score[0] < nWin && score[1] < nWin; actv = !actv) { int from, to; while (counter == 0) { if (counter1 == 1) { if (from == 0) { saveFile(actv, pit, score); break; } if (scanf("%d", &from) != 1 || from < 1 || from > 6 || (pit[(from - 1) + fix] <= 1 && temp > 1) || (pit[(from - 1) + fix] == 0 && temp == 1) ) { puts("Out of bounds, select pit (1-6): "); } else { counter = 1; } } } counter = 0; counter1 = 0; from -= 1; // 0 indexing from += fix; to = from; int nSow = pit[ from ]; pit[ from ] = 0; while (nSow) { //if more than 12 seeds, skip from pit if ((to = (to+1) % nPit) != from) { ++pit[ to ]; --nSow; } } while (nSow--) //moving pit[ to = (to+1)%nPit ]++; // condition true only while in opponent's range of pits for ( ; to/nOne != from/nOne; to = (to+(nPit-1))%nPit) // modulo -1 if (pit[ to ] == 2 || pit[ to ] == 3) { score[ actv ] += pit[ to ]; pit[ to ] = 0; } else break; }
问题根源分析
- break语句的副作用:输入
0触发保存后,break仅跳出内层的while (counter == 0)循环,但外层的落子逻辑(从from -= 1开始的代码)仍会执行。此时from值为0,经过from -=1变成-1,加上fix后会形成非法索引,错误修改pit数组,进而触发自动落子逻辑。 - 状态未正确重置:保存操作后没有标记“无需执行落子流程”,程序默认继续执行播种、收割逻辑,导致棋盘被意外修改。
修复方案
- 添加跳过标记:调用
saveFile后设置skipTurn标记,让外层循环直接跳过落子流程,切换到下一轮玩家回合。 - 修正输入处理顺序:先读取输入再判断是否为
0,避免from未初始化的问题。 - 修复saveFile的scanf错误:
scanf("%s", &fName);应改为scanf("%s", fName);,因为fName本身是数组指针,无需取地址,否则可能引发内存越界。
修改后的main函数相关部分示例:
for ( ; score[0] < nWin && score[1] < nWin; actv = !actv) { int from, to; int skipTurn = 0; // 添加跳过标记 while (counter == 0) { if (counter1 == 1) { if (scanf("%d", &from) != 1) { puts("Invalid input, try again: "); continue; } if (from == 0) { saveFile(actv, pit, score); skipTurn = 1; break; } if (from < 1 || from > 6 || (pit[(from - 1) + fix] <= 1 && temp > 1) || (pit[(from - 1) + fix] == 0 && temp == 1) ) { puts("Out of bounds, select pit (1-6): "); } else { counter = 1; } } } counter = 0; counter1 = 0; if (skipTurn) { continue; // 跳过落子流程,直接切换玩家 } from -= 1; // 0 indexing from += fix; to = from; // 剩余落子逻辑保持不变... }
内容的提问来源于stack exchange,提问作者ramwen0
相关产品推荐
相关产品推荐

