我一直在为Oware Abapa棋盘游戏的复制品工作,遇到了一个问题.我有一个saveState功能,可以将游戏板的当前状态保存到一个带有用户名的文件中,这一切都很好,但当循环结束时,我的游戏板会受到影响,而它应该保持不变. 下面是我的游戏板是如何设置的,p是PIT的缩写,s是分数的缩写.

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
    );
}

此外,以下是我的saveState函数:

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;的声明有关,但我不确定. 谢谢你的帮助!

推荐答案

保存游戏后,在读取from的值之前,从while循环中执行break.控制流向外部for循环的主体,它以虚假的未初始化值from继续,导致不稳定的行为,直到下一轮.

您绝对应该删除这条break语句.

还要注意,测试if (from == 0)在第一次迭代中具有未定义的行为,因为from未被初始化,因此它的值可以是任何值.如果您希望系统地保存游戏,请将其初始设置为0.您还可以判断从用户那里读取的值,并给出0个特殊的语义,比如保存游戏.为此,您应该将测试移到scanf()之后.

以下是该循环的修改版本:

            for (;;) {
                if (scanf("%d", &from) != 1) {
                    // input was not a number
                    int c;
                    printf("invalid input\n");
                    while ((c = getchar()) != EOF && c != '\n')
                        continue;
                    if (c == EOF)
                        exit(1);
                } else
                if (from == 0) {
                    // special value: save state
                    saveFile(actv, pit, score);
                } else
                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 {
                    break; 
                }
            }

C++相关问答推荐

C sscanf没有捕获第二个参数

C/C++中的状态库

为什么PLT表中没有push指令?

如何正确地索引C中的 struct 指针数组?

在Linux上使用vscode和lldb调试用Makefile编译的c代码

如何在提取的索引中分配空值?

指向不同类型的指针是否与公共初始序列规则匹配?

为四维数组中的Dim-1和Dim-3重新分配空间

使用Open62541向OPCUA服务器发送读请求时内存泄漏

我编写这段代码是为了判断一个数字是质数、阿姆斯特朗还是完全数,但由于某种原因,当我使用大数时,它不会打印出来

从文件到链表读取日期

如何不断地用C读取文件?

If语句默认为true

从管道读取数据时丢失

使用复合文字数组初始化的指针数组

在链表中插入一个值

当循环变量在溢出时未定义时,可以进行哪些优化?

Codewars Kata 掷骰子的不稳定行为

K&R 练习 1-24

米斯拉映射到 klocwork 违规行为