在C中创建数组中的特定值

jbose2ul  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(94)

我一直在用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;
}

字符串
我试过使用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;,但没有用。
运行当前代码实现时返回的一个示例是

可以看出,debug语句返回得很好,因为要清空的坑应该是player 1中的第一个(坑0),并且正确数量的种子被添加到player 0's deposit,但是从中取出种子的坑没有像它应该的那样被清空,并且表现得像正常的坑。
对于这个场景,我提供了以下输入:
球员0:3
1:1
球员0:4
一比三
球员0:2
在这里,捕获发生
此外,我注意到,即使条件满足,参与人1也不会从参与人0那里获得任何种子,如下面的图片

所示
这应该促使玩家1捕获2个种子,但它没有。

3xiyfsfu

3xiyfsfu1#

正如在一些评论中所指出的,你似乎混淆了布尔AND和OR的效果。(我最喜欢的盲点是混淆了整数除法(a/b)和模(a%b)的效果。我知道我想要什么,但我的手指键入了 other 运算符。)建议复习。
很久以前就看到过这个游戏的参考资料,你的代码很有趣。然而,实现给我的印象是一堆 * 难以辨别 * 的操作,涉及 * 太多 * 变量,每个变量的名字都 * 太长 。C不是COBOL,这个应用程序不需要长变量名。(当目的和范围受到限制时,我建议选择简洁而不是冗长。)
下面是原始代码的精华。值得注意的属性:
1.内部表示可以是任何最好的服务目的。一个单一的数组(12 pits)简化了种子分布的模 Package 。
1.将代码分解为函数是值得称赞的,但有时会使操作变得模糊,而不是帮助读者理解。
1.注解应该只解释不寻常的,而不是明显的(对熟悉语言的读者)。
1.下面使用单字节unsigned char表示 * 种子 * 的数量和分数(数据范围为048)。这允许memset()(库函数)初始化每个 * 坑 * 中的种子数量。
1.在阅读了这个游戏的Wikipedia页面之后,下面的代码似乎完全实现了得分(我希望是正确的)。
1.这个游戏是逆时针进行的。
您的代码printf()中的用户反馈给人的印象是,您花费了大量时间来实现特定的布局。
建议首先集中精力让程序逻辑按照需要工作。格言中有很多智慧,“
证据在布丁中,”和“ 外表可能是欺骗性的。”
出于教育目的:

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

字符串

编辑:

在对OP代码的修改中,我没有停下来意识到主循环条件是错误的!
应该是score[0] < 25 && score[1] < 25
根据维基百科,draw是可能的。当一个玩家获得25+ * 种子 * 时,该玩家已经**赢得了比赛。

修订版本:

这是一个棘手的游戏玩独奏,因为董事会的方向是“固定的”。思考左向右的一些动作,然后右向左的其他人。减缓测试时,错误。
下面是大致相同的代码修改,以便当前玩家从他们的Angular 看到棋盘“从左到右”。这个修改是为了演示扩展 * 紧凑 * 代码的灵活性。

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


玩得开心点!

相关问题