检查两个二维数组中是否有两个相同的值

Checking if there are two same values inside two 2D arrays

提问人:Fruitpunchsamurai 提问时间:11/4/2023 最后编辑:chqrlieFruitpunchsamurai 更新时间:11/5/2023 访问量:68

问:

我正在尝试用 c 创建一个蛇和梯子游戏。在蛇和梯子的游戏中,有梯子把你带到棋盘上,有蛇把你带下来。我正在做一个项目,其中我的板每行只能有一个上图块(梯子)和一个下图块(蛇)。我能够创建两个称为函数的函数,每个数组随机生成 6 个值,以确保我的板中只有一个向上图块和一个向下图块。然而,我的问题是,有时向上的瓷砖与向下的瓷砖具有相同的值。这意味着有时我的 up 数组中的某个元素会显示为我的 down 数组中的元素。我正在尝试创建一个函数来检查我的两个数组,称为 和。为什么它们是 2D 数组的原因是我希望一个数字是将玩家带到棋盘上或向下的图块,而另一个数字将是玩家将降落的图块。up_numdown_numup[][]down[][]

这是我到目前为止所做的检查功能。

void check(int up[][2], int down[][2])
{
    printf("\n\n");

    int h = 0, i, j, k, l, m = 0;
    int check[12];
    int check_up[6];
    int check_down[6];
    int counter = 0;

    for (k = 0; k < 6; k++) {
        if (counter == 0) {
            h = 0;
            for (i = 0; i < 3; i++) {
                for(j = 0; j < 2; j++) {
                    check_up[h++] = up[i][j];
                    check_down[h++] = down[i][j];
                }
            }
        } 

        counter++;
        for (j = 0; j < 6; j++) {
            if (check_up[k] == check_down[j]) {
                up_num(up);
                down_num(down);
                k = 0;
                counter = 0;
            }
        }
    }

    for (i = 0; i < 3; i++) {
        for (j = 0; j < 2; j++) {
            printf("%d, ", up[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");

    for (i = 0; i < 3; i++) {
        for (j = 0; j < 2; j++) {
            printf("%d, ", down[i][j]);
        }
        printf("\n");
    }
}

有时我仍然会得到重复的值,我想不出解决问题的方法。我尝试创建一个嵌套循环,每当找到重复值时就会重新启动,然后我调用我事先创建的两个函数来再次生成随机值,这将确保我的板中只有一个向上图块和一个向下图块。我确保检查我创建的两个函数是否是问题所在,但过了一会儿,我发现不是。我只是在检查 2D 数组的值时遇到了一个问题,以确保一个数组中的元素不会出现在另一个数组中。

C 函数 多维数组 嵌套

评论

1赞 Some programmer dude 11/4/2023
您确定对两者使用相同的变量吗?更重要的是,你真的应该增加两次(并跳过这些数组的每一秒元素,并且可能也会超出它们的界限)?hcheck_upcheck_downh
0赞 Fruitpunchsamurai 11/4/2023
@Someprogrammerdude我想问一下,你跳过数组的每个第二个元素是什么意思?
0赞 Some programmer dude 11/4/2023
假设 ,则将分配给 并将分配给 。您将分配给 和 的下一次小版本。等等。例如,您永远不会分配给 或。h == 0check_up[h++] = up[i][j];check_up[0]check_down[h++] = down[i][j];check_down[1]check_up[2]check_down[3]check_up[1]check_down[0]

答:

0赞 NoDakker 11/4/2023 #1

我试图通过为蛇和梯子创建一个二维数组来测试您的代码,但是缺少函数信息来获得干净的编译(例如,“up_num()”和“down_num()”函数没有定义)。通过试图解释你的最终目标是什么,即不在同一行中放置多个梯子或蛇,也不将梯子和蛇放在同一位置,执行这些测试的代码实际上似乎过于复杂。

我对这个测试函数应该做什么的解释可能有点偏离基础,但以下是该函数的重构版本以及一个“主”程序,该程序为蛇和梯子构建了一个简单的二维数组,然后测试了一些不同的场景。

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

#define ROWS 6                      /* To give flexibility to board size and design */
#define COLS 12

int check(int up[ROWS][COLS], int down[ROWS][COLS])
{
    int counterLadder = 0;
    int counterSnakes = 0;

    /* Testing for duplicate ladders and/or snakes in a row */

    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; j < COLS; j++)
        {
            if (up[i][j] == 1)
                counterLadder++;
            if (counterLadder > 1)
            {
                printf("More than one ladder was found in row %d\n", i);
                return 1;
            }
            if (down[i][j] == 1)
                counterSnakes++;
            if (counterSnakes > 1)
            {
                printf("More than one snake was found in row %d\n", i);
                return 1;
            }
        }
    }

    /* Checking to see that a ladder and a snake do not exist at the same location */

    counterLadder = 0;

    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; j < COLS; j++)
        {
            if ((up[i][j] == down[i][j]) && (up[i][j] == 1))
            {
                counterLadder++;
                printf("A ladder and a snake are located at row %d, column %d\n", i, j);
                return 1;
            }
        }

        if (counterLadder > 1)
            return 1;
    }

    printf("All clear\n");

    return 0;
}

int main()              /* Basically a simple test harness program to build and then test out location issues with the ladder and snake locations   */
{
    int Ladder[ROWS][COLS], Snakes[ROWS][COLS];

    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; j < COLS; j++)
        {
            Ladder[i][j] = 0;
            Snakes[i][j] = 0;
        }
    }

    if(check(Ladder, Snakes) == 1)
        printf("Some type of error occurred - retry\n");

    Ladder[2][4] = 1;
    Ladder[2][9] = 1;

    if(check(Ladder, Snakes) == 1)
        printf("Some type of error occurred - retry\n");

    Ladder[2][9] = 0;
    Snakes[2][4] = 1;

    if(check(Ladder, Snakes) == 1)
        printf("Some type of error occurred - retry\n");

    return 0;
}

很抱歉重构代码的长度,但我想给你整个事情作为思考的食粮。当我运行此示例时,创建了以下终端输出。

craig@Vera:~/C_Programs/Console/SnakesAndLadders/bin/Release$ ./SnakesAndLadders 
All clear
More than one ladder was found in row 2
Some type of error occurred - retry
A ladder and a snake are located at row 2, column 4
Some type of error occurred - retry

正如我所说,我可能在您的测试中遗漏了一些微妙的问题,但这似乎简化了重复和重叠的测试。把它当作你的闲暇时间。

0赞 Fe2O3 11/4/2023 #2

请原谅我这么说,但你可能从错误的方向来解决问题。与其组成一对板位置(或多对),不如在生成每个候选对时检查您的标准。

下面是一种仍然可以使用一些润色的方法。从堆中分配一个游戏板,将所有元素设置为 0。然后,随机选择单元格索引。如果单元格值为 0,则可以使用该单元格;一个非零值,指示该单元格已被使用,并且必须选择其他单元格。然后,通过一些复杂的求和和另一个随机偏移,找到另一个单元格。这两个细胞形成一对,是蛇或梯子的两端。请注意,存储在该货币对每个“末端”的值是其合作伙伴的地址。未提供用于确定配对在游戏过程中的角色的代码。calloc()

使用平移,因为数组实际上是一维的,但作得好像它是二维的。

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

#define ROWS 12
#define COLS 10
#define NELEM 12 // eg 6 snakes and 6 ladders

void show( int *pb, int rows, int cols ) {
    printf( "    " );
    for( int c = 0; c < cols; c++ ) // column titles
        printf( " %-2d ", c+1 );
    putchar( '\n' );

    for( int r = 0; r < rows; r++ ) {
        printf( "  %c ", r + 'A' ); // row title
        for( int c = 0; c < cols; c++ ) {
            if( !pb[ r * cols + c ] ) // vacant??
                printf( "=== " );
            else {
                int rw = pb[ r * cols + c ] / cols;
                int cw = pb[ r * cols + c ] % cols;
                printf( "%c%-2d ", rw + 'A', cw + 1 ); // terse address of partner
            }
        }
        putchar( '\n' );
    }
}

int *gen( int nElem, int rows, int cols ) {
    int n = rows * cols;
    int *pb = calloc( n, sizeof *pb ); // 1D version of 2D game board
    /* TODO: verify success */

    while( nElem ) {
        int e1, e2;
        e1 = 1 + (rand() % (n/2)); // one end
        if( !pb[e1] ) { // vacant??
            do {
                e2 = ( e1 + cols + rand()%(n-2*cols) )%n; // diff >= 1 row
            } while( pb[e2] ); // until another vacant found
            pb[e1] = e2; // address of partner
            pb[e2] = e1; // same
            nElem--;
        }
    }

    return pb; // game board established
}

int main( void ) {
    srand( time( 0 ) );

    int *pb = gen( NELEM, ROWS, COLS );
    show( pb, ROWS, COLS );
    free( pb );

    return 0;
}

输出:

     1   2   3   4   5   6   7   8   9   10
  A === === === === === === G6  === === ===
  B G9  H4  === H1  === === === H6  === ===
  C === I3  I5  I1  === === === === J1  === // eg "C2" <==> "I3". Snake or Ladder TBD
  D === === === === === === === === === ===
  E === === === K3  === K6  === === === ===
  F === === === === === L8  === === === ===
  G === === === === === A7  === === B1  ===
  H B4  === === B2  === B8  === === === ===
  I C4  === C2  === C3  === === === === ===
  J C9  === === === === === === === === ===
  K === === E4  === === E6  === === === ===
  L === === === === === === === F6  === ===

TODO:确保从已使用的单元格中排除开头的“square”和结尾的“square”。这两个“方块”都不应该是出发/到达方块。

事后思考:在建立了“n”对不冲突的对之后,认识到梯子的“顶端”是一个“中性”的目的地,就像蛇的“尾巴”一样。计算出一个寻找非零单元格的“奇偶校验”循环。如果单元及其伙伴都为非零,则根据奇偶校验计数器将一端重置为零(“中性”)。这样一来,除了那些指向目标伙伴的“特殊”单元格外,矩阵中充满了零。玩家要么爬上梯子,要么在从蛇上滑下来的位置上遭受令人心痛的损失。


更新:
通过一些意想不到的空闲时间,OP希望将每行限制为最多有一个蛇头或梯子底部(“单向虫洞”)的愿望已经得到解决。下面的注释代码似乎有效。还有一些“打印调试”语句可以打开以跟踪代码的执行。

主要增加的是两个“32位寄存器”;一个是蛇,一个是梯子。当确定虫洞进入单元(用于蛇或梯子)时,将设置与该单元的行对应的寄存器的一位。放置蛇/梯子的后续迭代会检查适当的位,拒绝每行具有多个虫洞条目的提供的单元对。(蛇头和一排的梯子底部是可以接受的。

电路板的尺寸(最大 32x32)和蛇/梯子对的数量可以通过命令行参数提供,虽然目前未选中,但必须有意义。为确保蛇/梯子的最小长度为 2,其中任何一个的数量都不能超过 # 行减去 2。否则,程序将无限循环尝试满足不可能的请求。

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

#define ROWS 12
#define COLS 10
#define NELEM 8 // eg 8 snakes and 8 ladders

void show( int *pb, int rows, int cols, char *title ) {
    puts( title );

    // column titles
    printf( "  " );
    for( int c = 0; c < cols; c++ )
        printf( "%-2d ", c );
    putchar( '\n' );

    for( int r = 0; r < rows; r++ ) {
        printf( "%c ", r + 'A' ); // row labels
        for( int c = 0; c < cols; c++ ) {
            if( !pb[ r * cols + c ] )
                printf( "== " ); // empty (might have shown destination)
            else {
                int pos = abs( pb[ r * cols + c ] ); // have -'ve destination values
                printf( "%c%-2d", 'A' + pos / cols, pos % cols );
            }
        }
        putchar( '\n' );
    }
}

int *gen( int nElem, int rows, int cols ) {
    int nSnk = nElem, nLdr = nElem;
    int n = rows * cols;
    int *pb = calloc( n, sizeof *pb ); // allocate the board

    nElem += nElem; // equal number of snakes and ladders
    uint32_t rowSnk = 0; // bitarray of used rows for snake heads
    uint32_t rowLdr = 0; // bitarray of used rows for ladder bottoms

    while( nSnk || nLdr ) { // until both down counters reach zero
        int lo = 1 + (rand() % (n-2-cols-cols)); // reduced range

        if( pb[lo] ) {
            // printf( "in use\n" );
            continue;
        }

        int hi = cols + cols + (rand() % (n-2-cols-cols));
        if( pb[hi] ) {
            // printf( "in use\n" );
            continue;
        }

        if( abs( (lo - hi) / cols ) < 2 ) {
            // printf( "too short; not interesting\n" );
            continue;
        }

#   define min(a,b) ( (a) < (b) ? (a) : (b) )
#   define max(a,b) ( (a) < (b) ? (b) : (a) )
        int dprt = nElem % 2 ? min(lo,hi) : max(lo,hi); // depart from
#   undef min
#   undef max
        int arrv = dprt == lo ? hi : lo; // arrive at
        int drow = dprt / cols; // departure row
        uint32_t *accum = dprt < arrv ? &rowLdr : &rowSnk; // point at counter

        if( *accum & (1 << drow) ) {
            // printf( "row used already" );
            continue;
        }

        // got a pair of cells that work...
        pb[dprt] =     arrv; // partner
        pb[arrv] = 0 - dprt; // partner encoded as -'ve
        *accum |= (1 << drow); // set applicable counter's bit marking departure row used
        if( dprt < arrv ) nLdr--; else nSnk--; // decrement either ladder or snake counter
        nElem--; // decrement affects parity. parity determines trying for snake or ladder

// some "useful" print debugging info...
// printf( "lo[%3d](%4d) hi[%3d](%4d)", lo, pb[lo], hi, pb[hi] );
// printf( " dprt(%3d) arrv(%3d) drow(%2d)", dprt, arrv, drow );
// printf( " - %-6s -", dprt < arrv ? "Ladder" : "Snake" );
// printf( "  rowSnk %04X  rowLdr %04X", rowSnk, rowLdr );
// printf( "  nSnk %d  nLdr %d ", nSnk, nLdr );
// putchar( '\n' );
    }

    return pb;
}

int *prune( int *pb, int n ) { // set those -'ve destinations to zero for display.
    while( n-- )
        if( pb[n] < 0 ) pb[n] = 0;

    return pb;
}

int main( void ) {
    srand( time( 0 ) );

    int *pb = gen( NELEM, ROWS, COLS );
    show( pb, ROWS, COLS, "departures & arrivals" ); // show both ends
    show( prune( pb, ROWS * COLS ), ROWS, COLS, "departures only" );

    free( pb );

    return 0;
}

输出:

departures & arrivals
  0  1  2  3  4  5  6  7  8  9
A == == J1 == == == == == == ==
B == D6 == I7 == K7 == H5 == ==
C == == == H3 F6 == E6 == == ==
D == G8 G2 == == == B1 == == ==
E == == == == == J0 C6 == == ==
F == == == == == J6 C4 == L7 ==
G == == D2 == I4 == == == D1 ==
H == == == C3 == B7 == == K9 ==
I == == == == G4 == == B3 == ==
J E5 A2 == L6 == == F5 == == ==
K == == == == == == == B5 == H8
L == == == == == == J3 F8 == ==
departures only
  0  1  2  3  4  5  6  7  8  9
A == == J1 == == == == == == ==
B == == == == == == == H5 == ==
C == == == H3 == == == == == ==
D == == G2 == == == B1 == == ==
E == == == == == J0 C6 == == ==
F == == == == == == C4 == L7 ==
G == == == == I4 == == == D1 ==
H == == == == == == == == K9 ==
I == == == == == == == B3 == ==
J == == == == == == F5 == == ==
K == == == == == == == B5 == ==
L == == == == == == J3 == == ==

另一种想法:在国际象棋中骑士的移动中(松散地)确定第 2 个单元格的模型(而不是生成第 2 个随机值)。“起始单元格左侧/右侧有 1 个单元格,向上或向下有 2 或 3 个单元格。”希望蛇或梯子有更多的垂直和更少的水平