Java はよくわかりませんが、C は知っているので、adk の魔方陣のアイデアを ( Hardwareguy の検索制限と共に) 試してみました。
// tic-tac-toe.c
// to compile:
// % gcc -o tic-tac-toe tic-tac-toe.c
// to run:
// % ./tic-tac-toe
#include <stdio.h>
// the two types of marks available
typedef enum { Empty=2, X=0, O=1, NumMarks=2 } Mark;
char const MarkToChar[] = "XO ";
// a structure to hold the sums of each kind of mark
typedef struct { unsigned char of[NumMarks]; } Sum;
// a cell in the board, which has a particular value
#define MAGIC_NUMBER 15
typedef struct {
Mark mark;
unsigned char const value;
size_t const num_sums;
Sum * const sums[4];
} Cell;
#define NUM_ROWS 3
#define NUM_COLS 3
// create a sum for each possible tic-tac-toe
Sum row[NUM_ROWS] = {0};
Sum col[NUM_COLS] = {0};
Sum nw_diag = {0};
Sum ne_diag = {0};
// initialize the board values so any row, column, or diagonal adds to
// MAGIC_NUMBER, and so they each record their sums in the proper rows, columns,
// and diagonals
Cell board[NUM_ROWS][NUM_COLS] = {
{
{ Empty, 8, 3, { &row[0], &col[0], &nw_diag } },
{ Empty, 1, 2, { &row[0], &col[1] } },
{ Empty, 6, 3, { &row[0], &col[2], &ne_diag } },
},
{
{ Empty, 3, 2, { &row[1], &col[0] } },
{ Empty, 5, 4, { &row[1], &col[1], &nw_diag, &ne_diag } },
{ Empty, 7, 2, { &row[1], &col[2] } },
},
{
{ Empty, 4, 3, { &row[2], &col[0], &ne_diag } },
{ Empty, 9, 2, { &row[2], &col[1] } },
{ Empty, 2, 3, { &row[2], &col[2], &nw_diag } },
}
};
// print the board
void show_board(void)
{
size_t r, c;
for (r = 0; r < NUM_ROWS; r++)
{
if (r > 0) { printf("---+---+---\n"); }
for (c = 0; c < NUM_COLS; c++)
{
if (c > 0) { printf("|"); }
printf(" %c ", MarkToChar[board[r][c].mark]);
}
printf("\n");
}
}
// run the game, asking the player for inputs for each side
int main(int argc, char * argv[])
{
size_t m;
show_board();
printf("Enter moves as \"<row> <col>\" (no quotes, zero indexed)\n");
for( m = 0; m < NUM_ROWS * NUM_COLS; m++ )
{
Mark const mark = (Mark) (m % NumMarks);
size_t c, r;
// read the player's move
do
{
printf("%c's move: ", MarkToChar[mark]);
fflush(stdout);
scanf("%d %d", &r, &c);
if (r >= NUM_ROWS || c >= NUM_COLS)
{
printf("illegal move (off the board), try again\n");
}
else if (board[r][c].mark != Empty)
{
printf("illegal move (already taken), try again\n");
}
else
{
break;
}
}
while (1);
{
Cell * const cell = &(board[r][c]);
size_t s;
// update the board state
cell->mark = mark;
show_board();
// check for tic-tac-toe
for (s = 0; s < cell->num_sums; s++)
{
cell->sums[s]->of[mark] += cell->value;
if (cell->sums[s]->of[mark] == MAGIC_NUMBER)
{
printf("tic-tac-toe! %c wins!\n", MarkToChar[mark]);
goto done;
}
}
}
}
printf("stalemate... nobody wins :(\n");
done:
return 0;
}
コンパイルとテストがうまくいきます。
% gcc -o tic-tac-toe tic-tac-toe.c
% 。/○×ゲーム
| | | |
---+---+---
| | | |
---+---+---
| | | |
移動を " " として入力します (引用符なし、ゼロ インデックス)
Xの手:1 2
| | | |
---+---+---
| | | | バツ
---+---+---
| | | |
Oの手:1 2
不正な移動 (既に取得済み)、再試行
Oの手:3 3
不正な動き (盤面外)、やり直してください
Oの手:2 2
| | | |
---+---+---
| | | | バツ
---+---+---
| | | | 〇
Xの手: 1 0
| | | |
---+---+---
X | | | バツ
---+---+---
| | | | 〇
Oの手:1 1
| | | |
---+---+---
X | お | バツ
---+---+---
| | | | 〇
Xの手: 0 0
X | | |
---+---+---
X | お | バツ
---+---+---
| | | | 〇
Oの手: 2 0
X | | |
---+---+---
X | お | バツ
---+---+---
お | | | 〇
Xの手:2 1
X | | |
---+---+---
X | お | バツ
---+---+---
お | X | 〇
Oの手:0 2
X | | | 〇
---+---+---
X | お | バツ
---+---+---
お | X | 〇
○×ゲーム!ああ、勝った!
% 。/○×ゲーム
| | | |
---+---+---
| | | |
---+---+---
| | | |
移動を " " として入力します (引用符なし、ゼロ インデックス)
Xの手: 0 0
X | | |
---+---+---
| | | |
---+---+---
| | | |
Oの手:0 1
X | お |
---+---+---
| | | |
---+---+---
| | | |
Xの手:0 2
X | お | バツ
---+---+---
| | | |
---+---+---
| | | |
Oの手:1 0
X | お | バツ
---+---+---
お | | |
---+---+---
| | | |
Xの手:1 1
X | お | バツ
---+---+---
お | X |
---+---+---
| | | |
Oの手: 2 0
X | お | バツ
---+---+---
お | X |
---+---+---
お | | |
Xの手:2 1
X | お | バツ
---+---+---
お | X |
---+---+---
お | X |
Oの手:2 2
X | お | バツ
---+---+---
お | X |
---+---+---
お | X | 〇
Xの手:1 2
X | お | バツ
---+---+---
お | X | バツ
---+---+---
お | X | 〇
膠着状態...誰も勝てません:(
%
楽しかったです、ありがとう!
実際、考えてみると、魔方陣は必要ありません。各行/列/対角線のカウントだけです。n
これは、魔方陣を×n
行列に一般化するよりも少し簡単ですn
。