提问人:Fruitpunchsamurai 提问时间:11/4/2023 最后编辑:chqrlieFruitpunchsamurai 更新时间:11/5/2023 访问量:68
检查两个二维数组中是否有两个相同的值
Checking if there are two same values inside two 2D arrays
问:
我正在尝试用 c 创建一个蛇和梯子游戏。在蛇和梯子的游戏中,有梯子把你带到棋盘上,有蛇把你带下来。我正在做一个项目,其中我的板每行只能有一个上图块(梯子)和一个下图块(蛇)。我能够创建两个称为函数的函数,每个数组随机生成 6 个值,以确保我的板中只有一个向上图块和一个向下图块。然而,我的问题是,有时向上的瓷砖与向下的瓷砖具有相同的值。这意味着有时我的 up 数组中的某个元素会显示为我的 down 数组中的元素。我正在尝试创建一个函数来检查我的两个数组,称为 和。为什么它们是 2D 数组的原因是我希望一个数字是将玩家带到棋盘上或向下的图块,而另一个数字将是玩家将降落的图块。up_num
down_num
up[][]
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 数组的值时遇到了一个问题,以确保一个数组中的元素不会出现在另一个数组中。
答:
我试图通过为蛇和梯子创建一个二维数组来测试您的代码,但是缺少函数信息来获得干净的编译(例如,“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。然后,随机选择单元格索引。如果单元格值为 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 个单元格。”希望蛇或梯子有更多的垂直和更少的水平。
上一个:collatz 函数中的分割错误
下一个:声明大型数组时出现堆栈溢出异常
评论
h
check_up
check_down
h
h == 0
check_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]