C-如何检查谁赢得了一场NxN游戏的O/X?
我正在做一个抽签游戏 我有一个功能,寻找一个赢家后,每一步是做 功能如下int-won(char-sym) 其中char sym是玩家的字母,例如X或O 我的游戏可以在任何尺寸的3-8板上玩,例如(3z3-8x8) 并且基于名为S[][] 大小也由用户选择,并存储在可验证的整数刻度中(全局可验证) 如何检查玩家是否获胜?(如果行、列或对角线都是同一个字母) 我只是震惊,因为我不知道如何使它适用于任何大小的表C-如何检查谁赢得了一场NxN游戏的O/X?,c,arrays,C,Arrays,我正在做一个抽签游戏 我有一个功能,寻找一个赢家后,每一步是做 功能如下int-won(char-sym) 其中char sym是玩家的字母,例如X或O 我的游戏可以在任何尺寸的3-8板上玩,例如(3z3-8x8) 并且基于名为S[][] 大小也由用户选择,并存储在可验证的整数刻度中(全局可验证) 如何检查玩家是否获胜?(如果行、列或对角线都是同一个字母) 我只是震惊,因为我不知道如何使它适用于任何大小的表 请帮忙 您可以检查水平线、垂直线和对角线。这些线与数组的大小无关。您应该能够在O(n)中
请帮忙 您可以检查水平线、垂直线和对角线。这些线与数组的大小无关。您应该能够在
O(n)
中执行此操作,其中n
是方块数,而不是像传统的3x3那样的O(1)
,并且只需检查每个方块,就可以不修改结构。你只需要检查一个方向,因为它是可交换的。像这样的,
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
struct Tic {
unsigned size;
char board[65];
};
static const char is_valid[] = "XO ";
/** This is a strict parser.
@param tic Overwriten with stdin on success. On failure, is corrupted.
@return Success.
@throws EDOM if the file is not correct, fgets, getc. */
static int load(struct Tic *const tic) {
char s[10];
size_t s_len, row = 0;
int is_size = 0;
assert(tic);
errno = 0;
tic->board[0] = '\0';
do {
if(!fgets(s, sizeof s, stdin)) return errno ? 0 : (errno = EDOM, 0);
if(s_len = strcspn(s, "\n\r\f"), s_len != strspn(s, is_valid))
return errno = EDOM, 0;
if(is_size) {
if(s_len != (size_t)tic->size) return errno = EDOM, 0;
} else {
if(s_len < 3 || s_len > 8) return errno = EDOM, 0;
tic->size = (unsigned)s_len;
is_size = 1;
}
s[s_len] = '\0';
strcat(tic->board, s);
} while(++row < tic->size);
/* Enforce EOF. */
if(getc(stdin) != EOF) return errno = EDOM, 0; else if(errno) return 0;
return 1;
}
/** Doesn't do bounds checks; should be inlined. */
static int is_owned(const struct Tic *const tic,
const size_t x, const size_t y, const char sym) {
return tic->board[y * tic->size + x] == sym;
}
/** @param tic A valid tic-tac-toe.
@param sym Either X or O.
@return Whether sym has won the game. */
static int won(const struct Tic *const tic, const char sym) {
const size_t size = tic->size;
size_t x, y;
int is_x, is_y;
assert(tic && (sym == 'X' || sym == 'O'));
for(y = 0; y < size; y++) {
for(x = 0; x < size; x++) {
if(!is_owned(tic, x, y, sym)) continue;
is_x = x < size - 2 ? 1 : 0;
is_y = y < size - 2 ? 1 : 0;
/* There are 3 cases. */
if(is_x && is_owned(tic, y, x + 1, sym)
&& is_owned(tic, y, x + 2, sym)) return 1;
if(is_y && is_owned(tic, y + 1, x, sym)
&& is_owned(tic, y + 2, x, sym)) return 1;
if(is_x && is_y && is_owned(tic, y + 1, x + 1, sym)
&& is_owned(tic, y + 2, x + 2, sym)) return 1;
}
}
return 0;
}
int main(void) {
struct Tic tic;
if(!load(&tic)) return perror("stdin"), EXIT_FAILURE;
printf("Xs won? %s.\n", won(&tic, 'X') ? "yes" : "no");
return EXIT_SUCCESS;
}
对于初学者,您可以尝试查看每一行、每一列和每一对角线。每次,您都会尝试在该行、列或对角线中找到足够长的
X
s或O
s的连续序列。
static int won_row(const struct Tic *const tic, const size_t y,
const char sym) {
const size_t size = tic->size;
size_t x;
for(x = 0; x < size; x++) if(!is_owned(tic, x, y, sym)) return 0;
return 1;
}
static int won_col(const struct Tic *const tic, const size_t x,
const char sym) {
const size_t size = tic->size;
size_t y;
for(y = 0; y < size; y++) if(!is_owned(tic, x, y, sym)) return 0;
return 1;
}
static int won_diag(const struct Tic *const tic, const char sym) {
const size_t size = tic->size;
size_t x;
for(x = 0; x < size; x++) if(!is_owned(tic, x, x, sym)) return 0;
return 1;
}
static int won_anti_diag(const struct Tic *const tic, const char sym) {
const size_t size = tic->size;
size_t x;
for(x = 0; x < size; x++) if(!is_owned(tic, x, size - x - 1, sym)) return 0;
return 1;
}
/** @param tic A valid tic-tac-toe.
@param sym Either X or O.
@return Whether sym has won the game. */
static int won(const struct Tic *const tic, const char sym) {
const size_t size = tic->size;
size_t x, y;
assert(tic && (sym == 'X' || sym == 'O'));
/* These do a short-circuit evaluation. */
for(y = 0; y < size; y++) if(won_row(tic, y, sym)) return 1;
for(x = 0; x < size; x++) if(won_col(tic, x, sym)) return 1;
return won_diag(tic, sym) || won_anti_diag(tic, sym);
}