Ben*_*key 89 java algorithm tic-tac-toe
我在Java中编写了一个井字游戏,我目前确定游戏结束的方法解释了游戏结束的以下可能情况:
不幸的是,为了做到这一点,它从表中读取了一组预定义的这些场景.考虑到电路板上只有9个空格,这并不一定是坏的,因此表格有点小,但有没有更好的算法来确定游戏是否结束?确定某人是否赢了是问题的关键,因为检查9个空格是否已满是微不足道的.
表方法可能是解决方案,但如果没有,那是什么?另外,如果电路板尺寸不大n=9
怎么办?如果它是一个更大的板,比如n=16
,n=25
等,造成连续放置物品的数量取胜是x=4
,x=5
等?一种用于所有人的通用算法n = { 9, 16, 25, 36 ... }
?
Har*_*guy 125
您知道获胜的移动只能在X或O进行最近移动之后发生,因此您只能搜索包含在该移动中的可选诊断的行/列,以在尝试确定获胜板时限制搜索空间.此外,由于在最后一次移动中,如果它不是一个获胜的移动,那么在抽签的Tic-tac-toe游戏中存在固定数量的移动它默认为抽奖游戏.
编辑:此代码用于n个n板,连续n个赢(3x3板请求连续3个,等等)
编辑:添加代码来检查反诊断,我无法找出一个非循环的方式来确定该点是否在反诊断,这就是为什么这一步缺失
public class TripleT {
enum State{Blank, X, O};
int n = 3;
State[][] board = new State[n][n];
int moveCount;
void Move(int x, int y, State s){
if(board[x][y] == State.Blank){
board[x][y] = s;
}
moveCount++;
//check end conditions
//check col
for(int i = 0; i < n; i++){
if(board[x][i] != s)
break;
if(i == n-1){
//report win for s
}
}
//check row
for(int i = 0; i < n; i++){
if(board[i][y] != s)
break;
if(i == n-1){
//report win for s
}
}
//check diag
if(x == y){
//we're on a diagonal
for(int i = 0; i < n; i++){
if(board[i][i] != s)
break;
if(i == n-1){
//report win for s
}
}
}
//check anti diag (thanks rampion)
if(x + y == n - 1){
for(int i = 0; i < n; i++){
if(board[i][(n-1)-i] != s)
break;
if(i == n-1){
//report win for s
}
}
}
//check draw
if(moveCount == (Math.pow(n, 2) - 1)){
//report draw
}
}
}
Run Code Online (Sandbox Code Playgroud)
adk*_*adk 34
你可以使用魔方#http://mathworld.wolfram.com/MagicSquare.html如果任何行,列或诊断加起来15,那么玩家就赢了.
CJ *_*net 20
这类似于Osama ALASSIRY的答案,但它为线性空间和恒定时间交换恒定空间和线性时间.也就是说,初始化后没有循环.
(0,0)
为每行,每列和两个对角线(对角线和反对角线)初始化一对.这些对表示(sum,sum)
相应的行,列或对角线中的片段的累积,其中
A piece from player A has value (1,0) A piece from player B has value (0,1)
当玩家放置一块时,更新相应的行对,列对和对角线对(如果在对角线上).如果任何新更新的行,列或对角线对等于(n,0)
或者(0,n)
然后分别赢得A或B.
渐近分析:
O(1) time (per move) O(n) space (overall)
对于内存使用,您使用4*(n+1)
整数.
two_elements*n_rows + two_elements*n_columns + two_elements*two_diagonals = 4*n + 4 integers = 4(n+1) integers
练习:你能看到如何在O(1)时间内进行抽签测试吗?如果是这样,你可以在平局的早期结束比赛.
Osa*_*eed 19
这个伪代码怎么样:
玩家在位置(x,y)放下一块后:
col=row=diag=rdiag=0
winner=false
for i=1 to n
if cell[x,i]=player then col++
if cell[i,y]=player then row++
if cell[i,i]=player then diag++
if cell[i,n-i+1]=player then rdiag++
if row=n or col=n or diag=n or rdiag=n then winner=true
Run Code Online (Sandbox Code Playgroud)
我使用char [n,n]数组,其中O,X和空格为空.
Gar*_*y C 19
超高效位板
让我们将游戏存储为二进制整数,并仅用一步来评估所有内容!
xxx xxx xxx
ooo ooo ooo
因此,棋盘位置只需 18 位即可表示:xoxoxo xoxoxo xoxoxo
但是,虽然这看起来很有效,但它并不能帮助我们确定胜利。我们需要一种更有用的位模式……它不仅可以对动作进行编码,还可以以合理的方式对行、列和对角线进行编码。
我会通过为每个棋盘位置使用一个巧妙的整数值来做到这一点。
选择更有用的表示
首先,我们需要一个董事会符号,以便我们可以讨论这个问题。因此,与国际象棋类似,让我们用字母对行进行编号,用数字对列进行编号 - 这样我们就知道我们正在谈论哪个方格
1 | 2 | 3 | |
---|---|---|---|
A | a1 | a2 | a3 |
乙 | b1 | b2 | b3 |
C | c1 | c2 | c3 |
让我们给每个值一个二进制值。
a1 = 100 000 000 100 000 000 100 000 ; Row A Col 1 (top left corner)
a2 = 010 000 000 000 100 000 000 000 ; Row A Col 2 (top edge)
a3 = 001 000 000 000 000 100 000 100 ; Row A Col 3 (top right corner)
b1 = 000 100 000 010 000 000 000 000 ; Row B Col 1 (left edge)
b2 = 000 010 000 000 010 000 010 010 ; Row B Col 2 (middle square)
b3 = 000 001 000 000 000 010 000 000 ; Row B Col 4 (right edge)
c1 = 000 000 100 001 000 000 000 001 ; Row C Col 1 (bottom left corner)
c2 = 000 000 010 000 001 000 000 000 ; Row C Col 2 (bottom edge)
c3 = 000 000 001 000 000 001 001 000 ; Row C Col 3 (bottom right corner)
Run Code Online (Sandbox Code Playgroud)
...其中,二进制值对位置出现的行、列和对角线进行编码。 (稍后我们将了解它是如何工作的)
我们将使用这些值构建游戏的两种表示形式,一种代表 X,一种代表 O
000 000 000 000 000 000 000 000
000 000 000 000 000 000 000 000
让我们跟随X的动作 (O也是同样的原理)
这对 X 的董事会价值有何影响:
a1 = 100 000 000 100 000 000 100 000
...或与a2 = 010 000 000 000 100 000 000 000
...或与a3 = 001 000 000 000 000 100 000 100
... 等于 :XB=111 000 000 100 100 100 100 100
从左到右阅读,我们看到 X 有:
111
(所有位置)第 1 行(\o/ 胜利,耶!)000
第 2 行(无位置)000
第 3 行(无位置)100
(一个位置)仅第 1 列的第一个位置100
(一个位置)仅第 1 列的第一个位置100
(一个位置)仅第 1 列的第一个位置100
(一个位置)仅对角线1的第一个位置100
(一个位置)仅对角线2的第一个位置您会注意到,每当 X(或 O)有获胜线时,他的棋盘值中也会有三个连续的位。准确地说,这三个位的位置决定了他在哪一行/哪一列/哪一条对角线上获胜。
因此,现在的技巧是找到一种方法来在单个操作中检查此(三个连续位设置)条件。
修改值以使检测更容易
为了帮助解决这个问题,让我们改变我们的位表示,以便三组之间始终有零(因为也是001 110
三个连续位 - 但它们不是有效的胜利......所以,固定的零间隔符会打破这些:0 001 0 110
)
因此,在添加一些空格零之后,我们可以确信 X 或 O 棋盘值中的任何三个连续设置位都表示获胜!
因此,我们的新二进制值(带零填充)如下所示:
a1 = 100 0 000 0 000 0 100 0 000 0 000 0 100 0 000 0
; 0x80080080(十六进制)a2 = 010 0 000 0 000 0 000 0 100 0 000 0 000 0 000 0
; 0x40008000a3 = 001 0 000 0 000 0 000 0 000 0 100 0 000 0 100 0
; 0x20000808b1 = 000 0 100 0 000 0 010 0 000 0 000 0 000 0 000 0
; 0x08040000b2 = 000 0 010 0 000 0 000 0 010 0 000 0 010 0 010 0
; 0x04004044b3 = 000 0 001 0 000 0 000 0 000 0 010 0 000 0 000 0
; 0x02000400c1 = 000 0 000 0 100 0 001 0 000 0 000 0 000 0 001 0
; 0x00820002c2 = 000 0 000 0 010 0 000 0 001 0 000 0 000 0 000 0
; 0x00402000c3 = 000 0 000 0 001 0 000 0 000 0 001 0 001 0 000 0
; 0x00200220您会注意到主板的每个“winline”现在都需要 4 位。
8 个 winlines x 每条 4 位 = 32 位!是不是很方便:)))))
解析
我们可以移动所有的位来寻找三个连续的位,但这将需要 32 次移位 x 2 个玩家……并且需要一个计数器来跟踪。很慢!
我们可以与 0xF 进行 AND 运算,查找值 8+4+2=14。这将允许我们一次检查 4 位。将班次减少四分之一。但同样,这很慢!
因此,让我们立即检查所有可能性......
超高效的胜利检测
想象一下我们想要评估 A3+A1+B2+C3 的情况(对角线获胜)
a1 = 100 0 000 0 000 0 100 0 000 0 000 0 100 0 000 0, OR
a3 = 001 0 000 0 000 0 000 0 000 0 100 0 000 0 100 0, OR
b2 = 000 0 010 0 000 0 000 0 010 0 000 0 010 0 010 0, OR
c3 = 000 0 000 0 001 0 000 0 000 0 001 0 001 0 000 0, =
XB = 101 0 010 0 001 0 100 0 010 0 101 0 111 0 110 0 (See the win, on Diagonal 1?)
Run Code Online (Sandbox Code Playgroud)
现在,让我们通过有效地将三位合并为一位来检查是否获胜......
只需使用:XB AND (XB << 1) AND (XB >> 1)
换句话说:XB ANDed with(XB左移)AND(XB右移)
让我们尝试一个例子......
10100100001010000100101011101100 ; whitespaces removed for easy shifting
(AND)
01001000010100001001010111011000 ; XB shifted left
(AND)
01010010000101000010010101110110 ; XB shifted left
(Equals)
00000000000000000000000001000000
Run Code Online (Sandbox Code Playgroud)
看到了吗?任何非零结果都意味着胜利!
但是,他们赢在哪里呢?
想知道他们赢在哪里吗?好吧,你可以使用第二个表:
0x40000000 = RowA
0x04000000 = RowB
0x00400000 = RowC
0x00040000 = Col1
0x00004000 = Col2
0x00000400 = Col3
0x00000040 = Diag1
0x00000004 = Diag2
Run Code Online (Sandbox Code Playgroud)
然而,我们可以比这更聪明,因为模式非常规则!
例如,在汇编中,您可以使用它BSF (Bit Scan Forward)
来查找前导零的数量。然后减去 2,然后减去 /4(右移 2) - 得到 0 到 8 之间的数字...您可以将其用作索引来查找 win 字符串数组:
{"wins the top row", "takes the middle row!", ... "steals the diagonal!" }
这使得整个游戏逻辑......从移动检查,到棋盘更新,一直到赢/输检测和适当的成功消息,都适合少数 ASM 指令。
...它小巧、高效且超快!
检查一个动作是否可以进行
显然,“X 的棋盘”与“O 的棋盘”进行 OR 运算 = 所有位置
因此,您可以很容易地检查移动是否有效。如果用户选择UpperLeft,则该位置具有整数值。只需用 (XB OR OB) 检查该值的“AND”...
...如果结果非零,则该位置已被使用。
结论
如果您正在寻找处理板的有效方法,请不要从板对象开始。尝试发现一些有用的抽象。
查看状态是否适合整数,并考虑要处理的“简单”位掩码是什么样的。通过巧妙地选择整数来表示动作、位置或棋盘……您可能会发现整个游戏可以非常有效地进行、评估和评分 - 使用简单的按位逻辑。
最后致歉
顺便说一句,我不是 StackOverflow 的常客,所以我希望这篇文章不会太混乱而难以理解。另外,请友善......“人类”是我的第二语言,我还不太流利;)
无论如何,我希望这对某人有帮助。
Jac*_*lan 11
以下是我为javascript中正在编写的项目编写的解决方案.如果你不介意几个阵列的内存成本,它可能是你会发现的最快,最简单的解决方案.它假设您知道最后一步的位置.
/*
* Determines if the last move resulted in a win for either player
* board: is an array representing the board
* lastMove: is the boardIndex of the last (most recent) move
* these are the boardIndexes:
*
* 0 | 1 | 2
* ---+---+---
* 3 | 4 | 5
* ---+---+---
* 6 | 7 | 8
*
* returns true if there was a win
*/
var winLines = [
[[1, 2], [4, 8], [3, 6]],
[[0, 2], [4, 7]],
[[0, 1], [4, 6], [5, 8]],
[[4, 5], [0, 6]],
[[3, 5], [0, 8], [2, 6], [1, 7]],
[[3, 4], [2, 8]],
[[7, 8], [2, 4], [0, 3]],
[[6, 8], [1, 4]],
[[6, 7], [0, 4], [2, 5]]
];
function isWinningMove(board, lastMove) {
var player = board[lastMove];
for (var i = 0; i < winLines[lastMove].length; i++) {
var line = winLines[lastMove][i];
if(player === board[line[0]] && player === board[line[1]]) {
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
Constant time solution, runs in O(8).
Store the state of the board as a binary number. The smallest bit (2^0) is the top left row of the board. Then it goes rightwards, then downwards.
I.E.
+-----------------+ | 2^0 | 2^1 | 2^2 | |-----------------| | 2^3 | 2^4 | 2^5 | |-----------------| | 2^6 | 2^7 | 2^8 | +-----------------+
Each player has their own binary number to represent the state (because tic-tac-toe) has 3 states (X, O & blank) so a single binary number won't work to represent the state of the board for multiple players.
For example, a board like:
+-----------+ | X | O | X | |-----------| | O | X | | |-----------| | | O | | +-----------+ 0 1 2 3 4 5 6 7 8 X: 1 0 1 0 1 0 0 0 0 奥:0 1 0 1 0 0 0 1 0
请注意,玩家 X 的位与玩家 O 的位不相交,这很明显,因为 X 不能将棋子放在 O 有棋子的地方,反之亦然。
为了检查玩家是否获胜,我们需要将该玩家覆盖的所有位置与我们知道的获胜位置进行比较。在这种情况下,最简单的方法是对玩家位置和获胜位置进行“与”门控,然后查看两者是否相等。
boolean isWinner(short X) {
for (int i = 0; i < 8; i++)
if ((X & winCombinations[i]) == winCombinations[i])
return true;
return false;
}
Run Code Online (Sandbox Code Playgroud)
例如。
电话:111001010 W: 111000000 // 获胜位置,第一行都相同。 ------------ &:111000000
注:X & W = W
,所以X处于胜利状态。
这是一个恒定时间解决方案,它仅取决于获胜位置的数量,因为应用与门是恒定时间操作并且获胜位置的数量是有限的。
它还简化了枚举所有有效板状态的任务,它们只是由 9 位表示的所有数字。但当然,您需要一个额外的条件来保证一个数字是有效的棋盘状态(例如,0b111111111
是一个有效的 9 位数字,但它不是有效的棋盘状态,因为 X 刚刚完成了所有回合)。
可能的获胜位置的数量可以即时生成,但无论如何它们都在这里。
short[] winCombinations = new short[] {
// each row
0b000000111,
0b000111000,
0b111000000,
// each column
0b100100100,
0b010010010,
0b001001001,
// each diagonal
0b100010001,
0b001010100
};
Run Code Online (Sandbox Code Playgroud)
要枚举所有板位置,您可以运行以下循环。尽管我将把确定一个数字是否是有效的棋盘状态留给其他人。
注意:(2**9 - 1) = (2**8) + (2**7) + (2**6) + ... (2**1) + (2**0)
for (short X = 0; X < (Math.pow(2,9) - 1); X++)
System.out.println(isWinner(X));
Run Code Online (Sandbox Code Playgroud)
小智 7
我刚刚为我的C编程类编写了这个.
我发布它是因为这里没有任何其他示例可以使用任何大小的矩形网格,并且任何数量的N -in-a-row连续标记都可以获胜.
你会在checkWinner()
函数中找到我的算法,例如它.它不使用魔术数字或任何想要检查胜利者的东西,它只是使用四个for循环 - 代码得到很好的评论,所以我会让它自己说话我想.
// This program will work with any whole number sized rectangular gameBoard.
// It checks for N marks in straight lines (rows, columns, and diagonals).
// It is prettiest when ROWS and COLS are single digit numbers.
// Try altering the constants for ROWS, COLS, and N for great fun!
// PPDs come first
#include <stdio.h>
#define ROWS 9 // The number of rows our gameBoard array will have
#define COLS 9 // The number of columns of the same - Single digit numbers will be prettier!
#define N 3 // This is the number of contiguous marks a player must have to win
#define INITCHAR ' ' // This changes the character displayed (a ' ' here probably looks the best)
#define PLAYER1CHAR 'X' // Some marks are more aesthetically pleasing than others
#define PLAYER2CHAR 'O' // Change these lines if you care to experiment with them
// Function prototypes are next
int playGame (char gameBoard[ROWS][COLS]); // This function allows the game to be replayed easily, as desired
void initBoard (char gameBoard[ROWS][COLS]); // Fills the ROWSxCOLS character array with the INITCHAR character
void printBoard (char gameBoard[ROWS][COLS]); // Prints out the current board, now with pretty formatting and #s!
void makeMove (char gameBoard[ROWS][COLS], int player); // Prompts for (and validates!) a move and stores it into the array
int checkWinner (char gameBoard[ROWS][COLS], int player); // Checks the current state of the board to see if anyone has won
// The starting line
int main (void)
{
// Inits
char gameBoard[ROWS][COLS]; // Our gameBoard is declared as a character array, ROWS x COLS in size
int winner = 0;
char replay;
//Code
do // This loop plays through the game until the user elects not to
{
winner = playGame(gameBoard);
printf("\nWould you like to play again? Y for yes, anything else exits: ");
scanf("%c",&replay); // I have to use both a scanf() and a getchar() in
replay = getchar(); // order to clear the input buffer of a newline char
// (http://cboard.cprogramming.com/c-programming/121190-problem-do-while-loop-char.html)
} while ( replay == 'y' || replay == 'Y' );
// Housekeeping
printf("\n");
return winner;
}
int playGame(char gameBoard[ROWS][COLS])
{
int turn = 0, player = 0, winner = 0, i = 0;
initBoard(gameBoard);
do
{
turn++; // Every time this loop executes, a unique turn is about to be made
player = (turn+1)%2+1; // This mod function alternates the player variable between 1 & 2 each turn
makeMove(gameBoard,player);
printBoard(gameBoard);
winner = checkWinner(gameBoard,player);
if (winner != 0)
{
printBoard(gameBoard);
for (i=0;i<19-2*ROWS;i++) // Formatting - works with the default shell height on my machine
printf("\n"); // Hopefully I can replace these with something that clears the screen for me
printf("\n\nCongratulations Player %i, you've won with %i in a row!\n\n",winner,N);
return winner;
}
} while ( turn < ROWS*COLS ); // Once ROWS*COLS turns have elapsed
printf("\n\nGame Over!\n\nThere was no Winner :-(\n"); // The board is full and the game is over
return winner;
}
void initBoard (char gameBoard[ROWS][COLS])
{
int row = 0, col = 0;
for (row=0;row<ROWS;row++)
{
for (col=0;col<COLS;col++)
{
gameBoard[row][col] = INITCHAR; // Fill the gameBoard with INITCHAR characters
}
}
printBoard(gameBoard); // Having this here prints out the board before
return; // the playGame function asks for the first move
}
void printBoard (char gameBoard[ROWS][COLS]) // There is a ton of formatting in here
{ // That I don't feel like commenting :P
int row = 0, col = 0, i=0; // It took a while to fine tune
// But now the output is something like:
printf("\n"); //
// 1 2 3
for (row=0;row<ROWS;row++) // 1 | |
{ // -----------
if (row == 0) // 2 | |
{ // -----------
printf(" "); // 3 | |
for (i=0;i<COLS;i++)
{
printf(" %i ",i+1);
}
printf("\n\n");
}
for (col=0;col<COLS;col++)
{
if (col==0)
printf("%i ",row+1);
printf(" %c ",gameBoard[row][col]);
if (col<COLS-1)
printf("|");
}
printf("\n");
if (row < ROWS-1)
{
for(i=0;i<COLS-1;i++)
{
if(i==0)
printf(" ----");
else
printf("----");
}
printf("---\n");
}
}
return;
}
void makeMove (char gameBoard[ROWS][COLS],int player)
{
int row = 0, col = 0, i=0;
char currentChar;
if (player == 1) // This gets the correct player's mark
currentChar = PLAYER1CHAR;
else
currentChar = PLAYER2CHAR;
for (i=0;i<21-2*ROWS;i++) // Newline formatting again :-(
printf("\n");
printf("\nPlayer %i, please enter the column of your move: ",player);
scanf("%i",&col);
printf("Please enter the row of your move: ");
scanf("%i",&row);
row--; // These lines translate the user's rows and columns numbering
col--; // (starting with 1) to the computer's (starting with 0)
while(gameBoard[row][col] != INITCHAR || row > ROWS-1 || col > COLS-1) // We are not using a do... while because
{ // I wanted the prompt to change
printBoard(gameBoard);
for (i=0;i<20-2*ROWS;i++)
printf("\n");
printf("\nPlayer %i, please enter a valid move! Column first, then row.\n",player);
scanf("%i %i",&col,&row);
row--; // See above ^^^
col--;
}
gameBoard[row][col] = currentChar; // Finally, we store the correct mark into the given location
return; // And pop back out of this function
}
int checkWinner(char gameBoard[ROWS][COLS], int player) // I've commented the last (and the hardest, for me anyway)
{ // check, which checks for backwards diagonal runs below >>>
int row = 0, col = 0, i = 0;
char currentChar;
if (player == 1)
currentChar = PLAYER1CHAR;
else
currentChar = PLAYER2CHAR;
for ( row = 0; row < ROWS; row++) // This first for loop checks every row
{
for ( col = 0; col < (COLS-(N-1)); col++) // And all columns until N away from the end
{
while (gameBoard[row][col] == currentChar) // For consecutive rows of the current player's mark
{
col++;
i++;
if (i == N)
{
return player;
}
}
i = 0;
}
}
for ( col = 0; col < COLS; col++) // This one checks for columns of consecutive marks
{
for ( row = 0; row < (ROWS-(N-1)); row++)
{
while (gameBoard[row][col] == currentChar)
{
row++;
i++;
if (i == N)
{
return player;
}
}
i = 0;
}
}
for ( col = 0; col < (COLS - (N-1)); col++) // This one checks for "forwards" diagonal runs
{
for ( row = 0; row < (ROWS-(N-1)); row++)
{
while (gameBoard[row][col] == currentChar)
{
row++;
col++;
i++;
if (i == N)
{
return player;
}
}
i = 0;
}
}
// Finally, the backwards diagonals:
for ( col = COLS-1; col > 0+(N-2); col--) // Start from the last column and go until N columns from the first
{ // The math seems strange here but the numbers work out when you trace them
for ( row = 0; row < (ROWS-(N-1)); row++) // Start from the first row and go until N rows from the last
{
while (gameBoard[row][col] == currentChar) // If the current player's character is there
{
row++; // Go down a row
col--; // And back a column
i++; // The i variable tracks how many consecutive marks have been found
if (i == N) // Once i == N
{
return player; // Return the current player number to the
} // winnner variable in the playGame function
} // If it breaks out of the while loop, there weren't N consecutive marks
i = 0; // So make i = 0 again
} // And go back into the for loop, incrementing the row to check from
}
return 0; // If we got to here, no winner has been detected,
} // so we pop back up into the playGame function
// The end!
// Well, almost.
// Eventually I hope to get this thing going
// with a dynamically sized array. I'll make
// the CONSTANTS into variables in an initGame
// function and allow the user to define them.
Run Code Online (Sandbox Code Playgroud)
如果电路板是n × n,那么有n行,n列和2个对角线.检查所有X或全O的每一个以找到胜利者.
如果它只需要x < n个连续的正方形来赢,那么它就会复杂一些.最明显的解决方案是检查每个x × x平方以获得胜利者.这里有一些代码可以证明这一点.
(我实际上并没有测试过这个*咳嗽*,但它确实在第一次尝试时编译,对我来说!)
public class TicTacToe
{
public enum Square { X, O, NONE }
/**
* Returns the winning player, or NONE if the game has
* finished without a winner, or null if the game is unfinished.
*/
public Square findWinner(Square[][] board, int lengthToWin) {
// Check each lengthToWin x lengthToWin board for a winner.
for (int top = 0; top <= board.length - lengthToWin; ++top) {
int bottom = top + lengthToWin - 1;
for (int left = 0; left <= board.length - lengthToWin; ++left) {
int right = left + lengthToWin - 1;
// Check each row.
nextRow: for (int row = top; row <= bottom; ++row) {
if (board[row][left] == Square.NONE) {
continue;
}
for (int col = left; col <= right; ++col) {
if (board[row][col] != board[row][left]) {
continue nextRow;
}
}
return board[row][left];
}
// Check each column.
nextCol: for (int col = left; col <= right; ++col) {
if (board[top][col] == Square.NONE) {
continue;
}
for (int row = top; row <= bottom; ++row) {
if (board[row][col] != board[top][col]) {
continue nextCol;
}
}
return board[top][col];
}
// Check top-left to bottom-right diagonal.
diag1: if (board[top][left] != Square.NONE) {
for (int i = 1; i < lengthToWin; ++i) {
if (board[top+i][left+i] != board[top][left]) {
break diag1;
}
}
return board[top][left];
}
// Check top-right to bottom-left diagonal.
diag2: if (board[top][right] != Square.NONE) {
for (int i = 1; i < lengthToWin; ++i) {
if (board[top+i][right-i] != board[top][right]) {
break diag2;
}
}
return board[top][right];
}
}
}
// Check for a completely full board.
boolean isFull = true;
full: for (int row = 0; row < board.length; ++row) {
for (int col = 0; col < board.length; ++col) {
if (board[row][col] == Square.NONE) {
isFull = false;
break full;
}
}
}
// The board is full.
if (isFull) {
return Square.NONE;
}
// The board is not full and we didn't find a solution.
else {
return null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
161413 次 |
最近记录: |