我一直在用C语言开发一个项目,用来实现非洲棋类游戏Oware,我正在努力实现捕获功能,因为种子所在的坑没有像应该的那样被清空.我的实现如下所示

#include <stdio.h>
#include <stdlib.h>

#define num_players 2
#define num_pits_player 6
#define num_seeds 4

struct gameState{
    int pits[num_players][num_pits_player]; //pits for the seeds
    int deposit[num_players]; //deposit for the pits
    int playerTurn; //keeping track of whose turn it is
};

void displayGame(struct gameState *game){
    printf("\n");
    printf("|--------|--|--player1--|--|--------|\n"
           "|score_p1|%2d|%2d|%2d|%2d|%2d|%2d|score_p0|\n"
           "|  %2d    |-----------------|   %2d   |\n"
           "|        |%2d|%2d|%2d|%2d|%2d|%2d|        |\n"
           "|--------|--|--player0--|--|--------|\n",
           game->pits[1][0], game->pits[1][1], game->pits[1][2], game->pits[1][3], game->pits[1][4], game->pits[1][5],
           game->deposit[1], game->deposit[0],
           game->pits[0][0], game->pits[0][1], game->pits[0][2], game->pits[0][3], game->pits[0][4], game->pits[0][5]);
}
void capture(struct gameState *game, int player, int pitToSow){
    int currentPit = (pitToSow + 1) % num_pits_player; //variable for the current pit
    int seedsInCurrentPit = game->pits[(player + currentPit / num_pits_player) % num_players][currentPit % num_pits_player]; //getting the seeds in the current pit
    int opponent = (player + 1) % num_players;

    if(seedsInCurrentPit == 2 || seedsInCurrentPit == 3) { //checking for conditions to sow
        game->deposit[player] += seedsInCurrentPit; //adding to deposit
        game->pits[opponent][seedsInCurrentPit] = 0; //dont work
        printf("player %d sowed %d seeds from \nplayer %d's pit number %d", player, seedsInCurrentPit, opponent, game->pits[opponent][seedsInCurrentPit]);
        //check suplementary rules
    }
}

void makeMove(struct gameState *game){
    int player = game->playerTurn;
    printf("Player %d's turn.\nPick a pit to sow(1-6): ", player);
    int pitToSow;
    if(scanf("%d", &pitToSow) != 1 || pitToSow < 1 || pitToSow > 6) { //validating if the pit is valid
        fprintf(stderr, "scanf failed\n");
        exit(1);
    }
    pitToSow--; // adjusting for zero-based indexing

    // Get the seeds from the selected pit
    int seedsToSow = game->pits[player][pitToSow];
    int lastPitSown = -1; // Initialize the variable to track the last pit sown
    int lastPlayer = player; // Initialize the variable to track the player of the last pit sown
    //zero out the pit
    game->pits[player][pitToSow] = 0;
    for(int currentPit = pitToSow + 1; seedsToSow > 0; currentPit++, seedsToSow--) {
        // Distribute one seed to the current pit - moving mechanic
        game->pits[(player + currentPit / num_pits_player) % num_players][currentPit % num_pits_player]++;
        lastPitSown = currentPit % num_pits_player; // Update the last pit sown
        lastPlayer = (player + currentPit / num_pits_player) % num_players; // Update the player of the last pit sown
    }

    if(lastPitSown >= 0 && lastPitSown < num_pits_player){ //if the last pit sown is in the scope of the array
        capture(game, player, pitToSow); //call capture function
    }

    //update turns
    game->playerTurn = (game->playerTurn + 1) % num_players;
}
void startGame(struct gameState *game){
    for(int player=0; player < num_players; player++){ //rotating the players
        for(int pit=0; pit < num_pits_player; pit++){ //populating each player's pits
            game->pits[player][pit] = num_seeds;
        }
        game->deposit[player] = 0; //init of deposits/score
    }
    game->playerTurn=0;
}

int main() {
    struct gameState game;
    //picking the game mode to play

    //game start - populate each pit w/ 4, deposit w/ 0
    startGame(&game);
    //display game
    displayGame(&game);
    while(game.deposit[0] <= 25 || game.deposit[1] <= 25){
        makeMove(&game);
        displayGame(&game);
    }

    return 0;
}

我try 使用game->pits[opponent][seedsInCurrentPit] = 0;,但即使我相信索引是正确的,代码也不能像预期的那样运行.我还添加了printf("player %d sowed %d seeds from \nplayer %d's pit number %d", player, seedsInCurrentPit, opponent, game->pits[opponent][seedsInCurrentPit]);作为调试语句,它似乎返回得很好,但是我需要清零的值(存放SeedsInCurrentPit的PIT)却不是这样. 最后,我试过使用game->pits[(player + currentPit / num_pits_player) % num_players][currentPit % num_pits_player] = 0;,但没有用.

An example for the return I get when I run my current code implementation is Test run example

As can be seen, the debug statement returns just fine, as the pit to be emptied should be the first of player 1(pit 0), and the correct number of seeds gets added to player 0's deposit, however the pit where the seeds are taken from isn't emptied as it should, and behaves like a normal pit.
For this scenario, I've fed the following input:
player 0: 3
player 1: 1
player 0: 4
player 1: 3
player 0: 2
Right here, capture happens

Furthermore, I've noticed that player 1 does not capture any seeds from player 0, even if conditions are met, as shown in the image below Player 1 error in capture

这本应促使玩家1捕获2个种子,但它没有.

推荐答案

正如几个注释中所指出的,您似乎混淆了布尔AND和OR的效果.(我最喜欢的盲点是将整数除法(a/b)和模数(a%b)的效果混淆在一起.我知道我想要什么,但我的手指打的是other操作员.)推荐复习.


很久以前就看到了这个游戏的参考资料,你的代码很有趣.然而,这个实现给我的印象是difficult-to-discern个操作的泥潭,涉及too many个变量,每个变量的名字都是far too long.C不是COBOL,这个应用程序不需要长变量名.(当目的和范围受到限制时,我建议 Select 简洁而不是冗长.

下面是您的原始代码的提炼.值得注意的属性:

  1. 内部表示可以是最适合该目的的任何形式.单个数组(12,pits个)简化了种子分配时的模数包装.
  2. 将代码分解到函数中是值得称赞的,但有时会使操作变得模糊,而不是帮助读者理解.
  3. comments 应该只解释不寻常的东西,而不是显而易见的东西(对熟悉这种语言的读者来说).
  4. 下面使用单字节unsigned char表示seeds的数字和分数(数据范围从048).这允许memset()(库函数)初始化每个pit中的种子数量.
  5. 在阅读了这个游戏的Wikipedia页面之后,下面的代码似乎完全实现了评分(我希望是正确的).可以在一个单层中从对手的几个坑中收集点.
  6. 这场比赛是counter-clockwise场比赛.

您的代码中的用户反馈- printf() -给人的印象是花费了大量时间来实现特定的布局.下面是这个版本的第trimmed页.

建议首先将重点放在让程序逻辑根据需要工作上.谚语"The proof is in the pudding,"和"Appearances can be deceiving."中蕴含着许多智慧.

作教育用途:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define nPlayer 2
#define nOne 6
#define nPit (2 * nOne)
#define nSeed 4

typedef unsigned char t_Pit;

void show( t_Pit p[], t_Pit s[] ) {
    printf(
        "\n"
        "------+-----player1-----+------\n"
        "      |%2d|%2d|%2d|%2d|%2d|%2d|\n"
        "P1 %2d +-----------------+ P0 %2d\n"
        "      |%2d|%2d|%2d|%2d|%2d|%2d|\n"
        "------+-----player0-----+------\t\t",
        p[ 5], p[ 4], p[ 3], p[ 2], p[ 1], p[ 0], // NB: custom indexing
        s[ 1], s[ 0],
        p[ 6], p[ 7], p[ 8], p[ 9], p[10], p[11] ); // note indexing
}

int main( void ) {
    t_Pit   pit[ nPit ] = { 0 },
            score[ nPlayer ] = { 0 };

    memset( pit, nSeed, sizeof pit );
    show( pit, score );

    /* note the use of the && operator here */
//  for( int player = 0; score[0] <= 25 && score[1] <= 25; player = !player ) { // wrong!
    for( int player = 0; score[0] < 25 && score[1] < 25; player = !player ) {
        printf( "%d selects pit (1-6): ", player );

        int from, to;
        if( scanf( "%d", &from ) != 1 || from < 1 || from > 6 ) {
            puts( "scanf failed" );
            return 1;
        }
        from -= 1; // 0 indexing

        if( player == 0 ) // change to "high range" of pits?
            from += nOne;
        to = from; // for now...

        int nSow = pit[ from ];
        pit[ from ] = 0;

        while( nSow-- )
            pit[ to = (to+1)%nPit ]++;

        // test = false when stepping out of opponents range of pits
        for( ; to/nOne != from/nOne; to = (to+(nPit-1))%nPit ) // modulo -1
            if( pit[ to ] == 2 || pit[ to ] == 3 ) {
                score[ player ] += pit[ to ];
                pit[ to ] = 0;
            } else break;

        show( pit, score );
    }

    return 0;
}

EDIT:
在对OP代码的修改中,我没有停下来意识到主循环条件是错误的!啊!

应该是score[0] < 25 && score[1] < 25

根据维基百科,draw是可能的.当一个玩家获得25+ seeds时,该玩家在游戏中获得won.


Revision:
单打独斗是一场棘手的游戏,因为棋盘方向是固定的.有些动作是从左向右思考,其他动作则是从右向左思考.在出现错误时减慢测试速度.

下面是经过修改的大致相同的代码,以便当前玩家从他们的Angular "从左到右"查看棋盘.这次修订是为了展示扩展compact代码的灵活性.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned char t_Pit;

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" : "selects pit (1-6): ";
    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"

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

int main( void ) {
    enum { nPlayer = 2, nOne = 6, nPit = (2*nOne), nSeed = 4, nWin = 25 }; // for @M.M.

    t_Pit score[ nPlayer ] = { 0 };
    t_Pit pit[ nPit ] = { 0 };
    memset( pit, nSeed, sizeof pit );


    int actv = 0;
    for( ; score[0] < nWin && score[1] < nWin; actv = !actv ) {
        show( actv, pit, score, 0 );

        int from, to;
        if( scanf( "%d", &from ) != 1 || from < 1 || from > 6 ) {
            puts( "scanf failed" );
            return 1;
        }
        from -= 1; // 0 indexing

        if( actv == 0 ) // change to "high range" of pits?
            from += nOne;
        to = from; // for now...

        int nSow = pit[ from ];
        pit[ from ] = 0;

        while( nSow-- )
            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;
    }
    show( !actv, pit, score, 1 ); // have a winner (require opp. parity)

    return 0;
}

玩得开心!

C++相关问答推荐

CC crate 示例不会与C函数链接

为什么listen()(在调用accept()之前)足以让应用程序完成3次握手?

为什么我得到更多的256假阳性在PKZIP解密密钥验证?

如何使用Python C API实现多线程程序?

C:scanf(%d&q;,...)输入只有一个减号

具有交换链获取和命令缓冲区提交的同步-危险-读后写错误

使用AVX2的英特尔2022编译器的NaN问题&;/fp:FAST

为什么该函数不将参数值保存到数据 struct 中?

如何在C++中处理按键

有什么方法可以将字符串与我们 Select 的子字符串分开吗?喜欢:SIN(LOG(10))

Cairo STM32MP1 cairo_Surface_WRITE_TO_PNG始终返回CAROLIO_STATUS_WRITE_ERROR

如何使用libgpio(d)为Raspberry Pi编译C程序?

为什么GCC-O1优化破解了这个代码,为了一个GameBoy高级只读存储器而修改了VRAM的循环?

在C程序中使用Beaglebone Black UART的问题

程序对大输入给出错误答案

Linux Posix消息队列

共享内存未授予父进程权限

C循环条件内的函数

如何找出C中分配在堆上的数组的大小?

System V 消息队列由于某种原因定期重置