Algoritma untuk Menentukan Tic Tac Toe Game Over

I've ditulis permainan tic-tac-toe di pulau Jawa, dan saya saat ini metode penentuan akhir dari permainan account untuk mengikuti skenario yang mungkin untuk permainan menjadi lebih:

  1. Papan penuh, dan tidak ada pemenang yang belum menyatakan: Permainan imbang.
  2. Salib telah menang.
  3. Lingkaran telah memenangkan.

Sayangnya, untuk melakukannya, ia membaca melalui sebuah set standar dari skenario ini dari sebuah tabel. Ini isn't selalu buruk mengingat bahwa hanya ada 9 ruang pada papan, dan dengan demikian meja agak kecil, tapi apakah ada yang lebih baik algoritmik cara untuk menentukan jika permainan berakhir? Penentuan apakah seseorang telah menang atau tidak adalah daging dari masalah, karena memeriksa jika 9 ruang yang penuh sepele.

Tabel metode yang mungkin bisa menjadi solusi, tapi jika tidak, apa? Juga, bagaimana jika dewan tidak ukuran n=9? Bagaimana jika itu adalah jauh lebih besar papan, mengatakan n=16, n=25, dan sebagainya, yang menyebabkan jumlah berturut-turut ditempatkan item untuk menang untuk x=4, x=5, dll? Algoritma umum untuk digunakan untuk semua n = { 9, 16, 25, 36 ... }?

Larutan

Anda tahu pemenang bergerak hanya bisa terjadi setelah X atau O telah membuat mereka yang paling baru-baru ini bergerak, sehingga anda hanya dapat mencari baris/kolom dengan opsional diag yang terdapat di dalam yang bergerak untuk membatasi pencarian anda ruang ketika mencoba untuk menentukan pemenang papan. Juga karena ada jumlah tetap bergerak dalam menggambar tic-tac-toe game setelah langkah terakhir dilakukan jika itu't pemenang bergerak's secara default imbang permainan.

edit: kode ini adalah untuk n dengan n papan dengan n berturut-turut untuk menang (3x3 papan requries 3 berturut-turut, dll)

edit: ditambahkan kode untuk memeriksa anti diag, aku tak't mengetahui non loop cara untuk menentukan apakah titik itu pada anti diag jadi thats mengapa langkah itu hilang

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
        }
    }
}
Komentar (18)

anda dapat menggunakan magic square http://mathworld.wolfram.com/MagicSquare.html jika setiap baris, kolom, atau diag menambahkan hingga 15 maka seorang pemain telah memenangkan.

Komentar (8)

Hal ini mirip dengan Osama ALASSIRY's answer, tetapi perdagangan yang konstan-ruang dan linear-waktu linear-ruang dan konstan-waktu. Artinya, ada's tidak ada perulangan setelah inisialisasi.

Menginisialisasi sepasang (0,0) untuk setiap baris, setiap kolom, dan dua diagonal (diagonal & anti-diagonal). Pasangan ini mewakili akumulasi (sum,sum) dari potongan-potongan di baris yang sesuai, kolom, atau diagonal, di mana

Sepotong dari pemain Yang memiliki nilai (1,0)
Sepotong dari pemain B memiliki nilai (0,1)

Ketika seorang pemain menempatkan sepotong, update baris yang sesuai pasangan, kolom pasangan, dan diagonal pasang (jika pada diagonal). Jika ada yang baru diperbarui baris, kolom, atau diagonal sepasang sama dengan baik (n,0) atau (0,n) maka A atau B yang menang, masing-masing.

Asymptotic analisis:

O(1) waktu (per langkah)
Ruang O(n) (keseluruhan)

Untuk penggunaan memori, anda menggunakan 4*(n+1) bilangan bulat.

two_elements*n_rows + two_elements*n_columns +
two_elements*two_diagonals = 4*n + 4 bilangan bulat = 4(n+1) bilangan bulat

Latihan: anda Dapat melihat bagaimana untuk menguji hasil imbang di O(1) waktu per-pindah? Jika demikian, anda dapat mengakhiri permainan awal yang menarik.

Komentar (1)

Bagaimana tentang hal ini pseudocode:

Setelah pemain meletakkan bagian pada posisi (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

I'a menggunakan sebuah array dari char [n,n], dengan O,X, dan ruang kosong.

  1. sederhana.
  2. Satu loop.
  3. Lima variabel sederhana: 4 bilangan bulat dan satu boolean.
  4. Timbangan untuk setiap ukuran n.
  5. Hanya memeriksa potongan saat ini.
  6. Tidak ada sihir. :)
Komentar (3)

Heres solusi saya bahwa saya menulis untuk sebuah proyek, saya'm bekerja di dalam javascript. Jika anda don't pikiran memori biaya dari beberapa array itu's mungkin yang tercepat dan paling sederhana solusi anda'll menemukan. Ini mengasumsikan anda tahu posisi terakhir bergerak.

/*
 * 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;
}
Komentar (3)

Saya hanya menulis ini untuk saya pemrograman C kelas.

Saya posting ini karena tidak ada contoh-contoh lain di sini akan bekerja dengan berbagai ukuran persegi panjang grid, dan jumlah N-in-a-baris berturut-tanda untuk menang.

Anda'll menemukan algoritma saya, seperti itu, di checkWinner() fungsi. Itu doesn't menggunakan angka ajaib atau sesuatu yang mewah untuk cek pemenang, itu hanya menggunakan empat untuk loop - kode baik berkomentar agar saya'll membiarkannya berbicara untuk dirinya sendiri saya kira.

// 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 
    #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 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.
Komentar (1)

Jika papan n &kali; n kemudian ada n baris, n kolom, dan 2 diagonal. Periksa masing-masing untuk semua-X's atau all-O's untuk menemukan pemenang.

Jika hanya dibutuhkan x < n kotak berturut-turut untuk menang, maka itu's sedikit lebih rumit. Solusi yang paling jelas adalah untuk memeriksa setiap x &kali; x square untuk pemenang. Berikut ini's beberapa kode yang menunjukkan bahwa.

(I didn't sebenarnya tes ini *batuk*, tapi itu did mengkompilasi pada percobaan pertama, yay aku!)


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 
Komentar (3)

Saya don't tahu Jawa yang baik, tapi aku tahu C, jadi saya mencoba adk's magic square idea (bersama dengan Hardwareguy's pencarian restriction).

// tic-tac-toe.c
// to compile:
//  % gcc -o tic-tac-toe tic-tac-toe.c
// to run:
//  % ./tic-tac-toe
#include 

// 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 \" \" (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;
}

Mengkompilasi dan tes dengan baik.

% gcc -o tic-tac-toe tic-tac-toe.c
% ./tic-tac-toe
| |
---+---+---
| |
---+---+---
| |
Masukkan bergerak sebagai " " (tanpa tanda kutip, nol diindeks)
X's 1 2
| |
---+---+---
| | X
---+---+---
| |
O's 1 2
ilegal bergerak (sudah diambil), coba lagi
O's bergerak: 3 3
ilegal bergerak (off the board), coba lagi
O's bergerak: 2 2
| |
---+---+---
| | X
---+---+---
| | O
X's bergerak: 1 0
| |
---+---+---
X | | X
---+---+---
| | O
O's bergerak: 1 1
| |
---+---+---
X | O | X
---+---+---
| | O
X's bergerak: 0 0
X | |
---+---+---
X | O | X
---+---+---
| | O
O's bergerak: 2 0
X | |
---+---+---
X | O | X
---+---+---
O | | O
X's bergerak: 2 1
X | |
---+---+---
X | O | X
---+---+---
O | X | O
O's bergerak: 0 2
X | | O
---+---+---
X | O | X
---+---+---
O | X | O
tic-tac-toe! O menang!
% ./tic-tac-toe
| |
---+---+---
| |
---+---+---
| |
Masukkan bergerak sebagai " " (tanpa tanda kutip, nol diindeks)
X's bergerak: 0 0
X | |
---+---+---
| |
---+---+---
| |
O's bergerak: 0 1
X | O |
---+---+---
| |
---+---+---
| |
X's bergerak: 0 2
X | O | X
---+---+---
| |
---+---+---
| |
O's bergerak: 1 0
X | O | X
---+---+---
O | |
---+---+---
| |
X's bergerak: 1 1
X | O | X
---+---+---
O | X |
---+---+---
| |
O's bergerak: 2 0
X | O | X
---+---+---
O | X |
---+---+---
O | |
X's bergerak: 2 1
X | O | X
---+---+---
O | X |
---+---+---
O | X |
O's bergerak: 2 2
X | O | X
---+---+---
O | X |
---+---+---
O | X | O
X's 1 2
X | O | X
---+---+---
O | X | X
---+---+---
O | X | O
buntu... tidak ada yang menang :(
%
Itu menyenangkan, terima kasih!

Sebenarnya, berpikir tentang hal itu, anda don't perlu sihir persegi, hanya dihitung untuk setiap baris/kolom/diagonal. Ini adalah sedikit lebih mudah daripada generalisasi persegi ajaib untuk n &kali; n matrik, karena anda hanya perlu hitungan ke n.

Komentar (0)

Saya ditanya pertanyaan yang sama di salah satu wawancara saya. Pikiran saya: Menginisialisasi matriks dengan 0. Tetap 3 array 1)sum_row (size n) 2) sum_column (size n) 3) diagonal (size 2)

Untuk masing-masing bergerak dengan (X) pengurangan kotak value dengan 1 dan untuk setiap langkah (0) increment dengan 1. Pada setiap titik jika baris/kolom/diagonal yang telah dimodifikasi di saat ini bergerak memiliki jumlah yang baik -3 atau +3 berarti seseorang telah memenangkan permainan. Untuk menarik kita dapat menggunakan pendekatan di atas untuk menjaga moveCount variabel.

Apakah anda pikir saya kehilangan sesuatu ?

Edit: yang Sama dapat digunakan untuk nxn matrix. Jumlah yang harus menjadi +3 atau -3.

Komentar (0)

non-loop cara untuk menentukan apakah titik itu pada anti diag:

`if (x + y == n - 1)`
Komentar (0)

Saya terlambat partai, tapi saya ingin menunjukkan salah satu manfaat yang saya temukan untuk menggunakan magic square, yaitu bahwa hal itu dapat digunakan untuk mendapatkan referensi ke alun-alun yang akan menyebabkan menang atau rugi pada giliran berikutnya, bukan hanya digunakan untuk menghitung ketika permainan berakhir.

Mengambil ini magic square:

4 9 2
3 5 7
8 1 6

Pertama, mendirikan sebuah nilai array yang bertambah setiap kali bergerak dibuat. Lihat jawaban untuk rincian. Sekarang jika kita bermain secara ilegal X dua kali berturut-turut di [0,0] dan [0,1], maka nilai array terlihat seperti ini:

[7, 0, 0, 4, 3, 0, 4, 0];

Dan dewan terlihat seperti ini:

X . .
X . .
. . .

Kemudian, yang harus kita lakukan dalam rangka untuk mendapatkan referensi ke alun-alun untuk menang/blok adalah:

get_winning_move = function() {
  for (var i = 0, i < scores.length; i++) {
    // keep track of the number of times pieces were added to the row
    // subtract when the opposite team adds a piece
    if (scores[i].inc === 2) {
      return 15 - state[i].val; // 8
    }
  }
}

Dalam kenyataannya, pelaksanaan memerlukan beberapa trik tambahan, seperti penanganan bernomor kunci (JavaScript), tapi saya menemukan itu cukup sederhana dan menikmati rekreasi matematika.

Komentar (0)

Saya membuat beberapa optimasi di row, col, diagonal pemeriksaan. Terutama diputuskan dalam pertama nested loop jika kita perlu memeriksa kolom tertentu atau diagonal. Jadi, kita menghindari memeriksa kolom atau diagonal menghemat waktu. Hal ini membuat dampak besar ketika ukuran papan yang lebih banyak dan jumlah yang signifikan dari sel-sel yang tidak diisi.

Berikut ini adalah kode java untuk itu.

    int gameState(int values[][], int boardSz) {

    boolean colCheckNotRequired[] = new boolean[boardSz];//default is false
    boolean diag1CheckNotRequired = false;
    boolean diag2CheckNotRequired = false;
    boolean allFilled = true;

    int x_count = 0;
    int o_count = 0;
    /* Check rows */
    for (int i = 0; i < boardSz; i++) {
        x_count = o_count = 0;
        for (int j = 0; j < boardSz; j++) {
            if(values[i][j] == x_val)x_count++;
            if(values[i][j] == o_val)o_count++;
            if(values[i][j] == 0)
            {
                colCheckNotRequired[j] = true;
                if(i==j)diag1CheckNotRequired = true;
                if(i + j == boardSz - 1)diag2CheckNotRequired = true;
                allFilled = false;
                //No need check further
                break;
            }
        }
        if(x_count == boardSz)return X_WIN;
        if(o_count == boardSz)return O_WIN;         
    }

    /* check cols */
    for (int i = 0; i < boardSz; i++) {
        x_count = o_count = 0;
        if(colCheckNotRequired[i] == false)
        {
            for (int j = 0; j < boardSz; j++) {
                if(values[j][i] == x_val)x_count++;
                if(values[j][i] == o_val)o_count++;
                //No need check further
                if(values[i][j] == 0)break;
            }
            if(x_count == boardSz)return X_WIN;
            if(o_count == boardSz)return O_WIN;
        }
    }

    x_count = o_count = 0;
    /* check diagonal 1 */
    if(diag1CheckNotRequired == false)
    {
        for (int i = 0; i < boardSz; i++) {
            if(values[i][i] == x_val)x_count++;
            if(values[i][i] == o_val)o_count++;
            if(values[i][i] == 0)break;
        }
        if(x_count == boardSz)return X_WIN;
        if(o_count == boardSz)return O_WIN;
    }

    x_count = o_count = 0;
    /* check diagonal 2 */
    if( diag2CheckNotRequired == false)
    {
        for (int i = boardSz - 1,j = 0; i >= 0 && j < boardSz; i--,j++) {
            if(values[j][i] == x_val)x_count++;
            if(values[j][i] == o_val)o_count++;
            if(values[j][i] == 0)break;
        }
        if(x_count == boardSz)return X_WIN;
        if(o_count == boardSz)return O_WIN;
        x_count = o_count = 0;
    }

    if( allFilled == true)
    {
        for (int i = 0; i < boardSz; i++) {
            for (int j = 0; j < boardSz; j++) {
                if (values[i][j] == 0) {
                    allFilled = false;
                    break;
                }
            }

            if (allFilled == false) {
                break;
            }
        }
    }

    if (allFilled)
        return DRAW;

    return INPROGRESS;
}
Komentar (0)

Saya suka algoritma ini karena menggunakan 1x9 vs 3x3 representasi dari papan.

private int[] board = new int[9];
private static final int[] START = new int[] { 0, 3, 6, 0, 1, 2, 0, 2 };
private static final int[] INCR  = new int[] { 1, 1, 1, 3, 3, 3, 4, 2 };
private static int SIZE = 3;
/**
 * Determines if there is a winner in tic-tac-toe board.
 * @return {@code 0} for draw, {@code 1} for 'X', {@code -1} for 'Y'
 */
public int hasWinner() {
    for (int i = 0; i < START.length; i++) {
        int sum = 0;
        for (int j = 0; j < SIZE; j++) {
            sum += board[START[i] + j * INCR[i]];
        }
        if (Math.abs(sum) == SIZE) {
            return sum / SIZE;
        }
    }
    return 0;
}
Komentar (2)

Berikut ini adalah solusi saya menggunakan 2 dimensi array:

private static final int dimension = 3;
private static final int[][] board = new int[dimension][dimension];
private static final int xwins = dimension * 1;
private static final int owins = dimension * -1;

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int count = 0;
    boolean keepPlaying = true;
    boolean xsTurn = true;
    while (keepPlaying) {
        xsTurn = (count % 2 == 0);
        System.out.print("Enter i-j in the format:");
        if (xsTurn) {
            System.out.println(" X plays: ");
        } else {
            System.out.println(" O plays: ");
        }
        String result = null;
        while (result == null) {
            result = parseInput(scanner, xsTurn);
        }
        String[] xy = result.split(",");
        int x = Integer.parseInt(xy[0]);
        int y = Integer.parseInt(xy[1]);
        keepPlaying = makeMove(xsTurn, x, y);
        count++;
    }
    if (xsTurn) {
        System.out.print("X");
    } else {
        System.out.print("O");
    }
    System.out.println(" WON");
    printArrayBoard(board);
}

private static String parseInput(Scanner scanner, boolean xsTurn) {
    String line = scanner.nextLine();
    String[] values = line.split("-");
    int x = Integer.parseInt(values[0]);
    int y = Integer.parseInt(values[1]);
    boolean alreadyPlayed = alreadyPlayed(x, y);
    String result = null;
    if (alreadyPlayed) {
        System.out.println("Already played in this x-y. Retry");
    } else {
        result = "" + x + "," + y;
    }
    return result;
}

private static boolean alreadyPlayed(int x, int y) {
    System.out.println("x-y: " + x + "-" + y + " board[x][y]: " + board[x][y]);
    if (board[x][y] != 0) {
        return true;
    }
    return false;
}

private static void printArrayBoard(int[][] board) {
    for (int i = 0; i < dimension; i++) {
        int[] height = board[i];
        for (int j = 0; j < dimension; j++) {
            System.out.print(height[j] + " ");
        }
        System.out.println();
    }
}

private static boolean makeMove(boolean xo, int x, int y) {
    if (xo) {
        board[x][y] = 1;
    } else {
        board[x][y] = -1;
    }
    boolean didWin = checkBoard();
    if (didWin) {
        System.out.println("keep playing");
    }
    return didWin;
}

private static boolean checkBoard() {
    //check horizontal
    int[] horizontalTotal = new int[dimension];
    for (int i = 0; i < dimension; i++) {
        int[] height = board[i];
        int total = 0;
        for (int j = 0; j < dimension; j++) {
            total += height[j];
        }
        horizontalTotal[i] = total;
    }
    for (int a = 0; a < horizontalTotal.length; a++) {
        if (horizontalTotal[a] == xwins || horizontalTotal[a] == owins) {
            System.out.println("horizontal");
            return false;
        }
    }
    //check vertical
    int[] verticalTotal = new int[dimension];

    for (int j = 0; j < dimension; j++) {
        int total = 0;
        for (int i = 0; i < dimension; i++) {
            total += board[i][j];
        }
        verticalTotal[j] = total;
    }
    for (int a = 0; a < verticalTotal.length; a++) {
        if (verticalTotal[a] == xwins || verticalTotal[a] == owins) {
            System.out.println("vertical");
            return false;
        }
    }
    //check diagonal
    int total1 = 0;
    int total2 = 0;
    for (int i = 0; i < dimension; i++) {
        for (int j = 0; j < dimension; j++) {
            if (i == j) {
                total1 += board[i][j];
            }
            if (i == (dimension - 1 - j)) {
                total2 += board[i][j];
            }
        }
    }
    if (total1 == xwins || total1 == owins) {
        System.out.println("diagonal 1");
        return false;
    }
    if (total2 == xwins || total2 == owins) {
        System.out.println("diagonal 2");
        return false;
    }
    return true;
}
Komentar (0)

Pilihan lain: membuat tabel dengan kode. Hingga simetri, hanya ada tiga cara untuk menang: ujung baris, baris tengah, atau diagonal. Mengambil orang-orang tiga dan berputar mereka di sekitar setiap cara yang mungkin:

def spin(g): return set([g, turn(g), turn(turn(g)), turn(turn(turn(g)))])
def turn(g): return tuple(tuple(g[y][x] for y in (0,1,2)) for x in (2,1,0))

X,s = 'X.'
XXX = X, X, X
sss = s, s, s

ways_to_win = (  spin((XXX, sss, sss))
               | spin((sss, XXX, sss))
               | spin(((X,s,s),
                       (s,X,s),
                       (s,s,X))))

Simetri-simetri ini dapat memiliki lebih banyak kegunaan dalam permainan-bermain kode: jika anda mendapatkan ke papan anda've sudah melihat diputar versi, anda hanya dapat mengambil nilai yang di-cache atau cache terbaik berpindah dari yang satu (dan unrotate kembali). Hal ini biasanya jauh lebih cepat daripada mengevaluasi permainan subtree.

(Membalik kiri dan kanan dapat membantu dengan cara yang sama; itu't dibutuhkan di sini karena mengatur rotasi dari pola kemenangan adalah cermin-simetris.)

Komentar (0)

Berikut ini adalah solusi saya datang dengan, ini menyimpan simbol-simbol sebagai karakter dan menggunakan char's int nilai untuk mengetahui apakah X atau O telah memenangkan (lihat Wasit's kode)

public class TicTacToe {
    public static final char BLANK = '\u0000';
    private final char[][] board;
    private int moveCount;
    private Referee referee;

    public TicTacToe(int gridSize) {
        if (gridSize < 3)
            throw new IllegalArgumentException("TicTacToe board size has to be minimum 3x3 grid");
        board = new char[gridSize][gridSize];
        referee = new Referee(gridSize);
    }

    public char[][] displayBoard() {
        return board.clone();
    }

    public String move(int x, int y) {
        if (board[x][y] != BLANK)
            return "(" + x + "," + y + ") is already occupied";
        board[x][y] = whoseTurn();
        return referee.isGameOver(x, y, board[x][y], ++moveCount);
    }

    private char whoseTurn() {
        return moveCount % 2 == 0 ? 'X' : 'O';
    }

    private class Referee {
        private static final int NO_OF_DIAGONALS = 2;
        private static final int MINOR = 1;
        private static final int PRINCIPAL = 0;
        private final int gridSize;
        private final int[] rowTotal;
        private final int[] colTotal;
        private final int[] diagonalTotal;

        private Referee(int size) {
            gridSize = size;
            rowTotal = new int[size];
            colTotal = new int[size];
            diagonalTotal = new int[NO_OF_DIAGONALS];
        }

        private String isGameOver(int x, int y, char symbol, int moveCount) {
            if (isWinningMove(x, y, symbol))
                return symbol + " won the game!";
            if (isBoardCompletelyFilled(moveCount))
                return "Its a Draw!";
            return "continue";
        }

        private boolean isBoardCompletelyFilled(int moveCount) {
            return moveCount == gridSize * gridSize;
        }

        private boolean isWinningMove(int x, int y, char symbol) {
            if (isPrincipalDiagonal(x, y) && allSymbolsMatch(symbol, diagonalTotal, PRINCIPAL))
                return true;
            if (isMinorDiagonal(x, y) && allSymbolsMatch(symbol, diagonalTotal, MINOR))
                return true;
            return allSymbolsMatch(symbol, rowTotal, x) || allSymbolsMatch(symbol, colTotal, y);
        }

        private boolean allSymbolsMatch(char symbol, int[] total, int index) {
            total[index] += symbol;
            return total[index] / gridSize == symbol;
        }

        private boolean isPrincipalDiagonal(int x, int y) {
            return x == y;
        }

        private boolean isMinorDiagonal(int x, int y) {
            return x + y == gridSize - 1;
        }
    }
}

Juga di sini adalah unit saya tes untuk memvalidasi itu benar-benar bekerja

import static com.agilefaqs.tdd.demo.TicTacToe.BLANK;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class TicTacToeTest {
    private TicTacToe game = new TicTacToe(3);

    @Test
    public void allCellsAreEmptyInANewGame() {
        assertBoardIs(new char[][] { { BLANK, BLANK, BLANK },
                { BLANK, BLANK, BLANK },
                { BLANK, BLANK, BLANK } });
    }

    @Test(expected = IllegalArgumentException.class)
    public void boardHasToBeMinimum3x3Grid() {
        new TicTacToe(2);
    }

    @Test
    public void firstPlayersMoveMarks_X_OnTheBoard() {
        assertEquals("continue", game.move(1, 1));
        assertBoardIs(new char[][] { { BLANK, BLANK, BLANK },
                { BLANK, 'X', BLANK },
                { BLANK, BLANK, BLANK } });
    }

    @Test
    public void secondPlayersMoveMarks_O_OnTheBoard() {
        game.move(1, 1);
        assertEquals("continue", game.move(2, 2));
        assertBoardIs(new char[][] { { BLANK, BLANK, BLANK },
                { BLANK, 'X', BLANK },
                { BLANK, BLANK, 'O' } });
    }

    @Test
    public void playerCanOnlyMoveToAnEmptyCell() {
        game.move(1, 1);
        assertEquals("(1,1) is already occupied", game.move(1, 1));
    }

    @Test
    public void firstPlayerWithAllSymbolsInOneRowWins() {
        game.move(0, 0);
        game.move(1, 0);
        game.move(0, 1);
        game.move(2, 1);
        assertEquals("X won the game!", game.move(0, 2));
    }

    @Test
    public void firstPlayerWithAllSymbolsInOneColumnWins() {
        game.move(1, 1);
        game.move(0, 0);
        game.move(2, 1);
        game.move(1, 0);
        game.move(2, 2);
        assertEquals("O won the game!", game.move(2, 0));
    }

    @Test
    public void firstPlayerWithAllSymbolsInPrincipalDiagonalWins() {
        game.move(0, 0);
        game.move(1, 0);
        game.move(1, 1);
        game.move(2, 1);
        assertEquals("X won the game!", game.move(2, 2));
    }

    @Test
    public void firstPlayerWithAllSymbolsInMinorDiagonalWins() {
        game.move(0, 2);
        game.move(1, 0);
        game.move(1, 1);
        game.move(2, 1);
        assertEquals("X won the game!", game.move(2, 0));
    }

    @Test
    public void whenAllCellsAreFilledTheGameIsADraw() {
        game.move(0, 2);
        game.move(1, 1);
        game.move(1, 0);
        game.move(2, 1);
        game.move(2, 2);
        game.move(0, 0);
        game.move(0, 1);
        game.move(1, 2);
        assertEquals("Its a Draw!", game.move(2, 0));
    }

    private void assertBoardIs(char[][] expectedBoard) {
        assertArrayEquals(expectedBoard, game.displayBoard());
    }
}

Solusi lengkap: https://github.com/nashjain/tictactoe/tree/master/java

Komentar (0)

Bagaimana pendekatan berikut untuk 9 slot? Menyatakan 9 integer variabel untuk 3x3 matrix (a1,a2....a9) dimana a1,a2,a3 mewakili baris-1 dan a1,a4,a7 akan membentuk kolom-1 (anda mendapatkan ide). Gunakan '1' untuk menunjukkan Pemain-1 dan '2' untuk menunjukkan Pemain-2.

Ada 8 kemungkinan menang kombinasi: Win-1: a1+a2+a3 (jawaban bisa 3 atau 6 berdasarkan pada pemain mana yang tidak) Menang-2: a4+a5+a6 Win-3: a7+a8+a9 Win-4: a1+a4+a7 .... Win-7: a1+a5+a9 Win-8: a3+a5+a7

Sekarang kita tahu bahwa jika pemain satu salib a1 maka kita perlu mengevaluasi kembali jumlah dari 3 variabel: Win-1, Win-4 dan Win-7. Mana 'Win-?' variabel mencapai 3 atau 6 pertama memenangkan permainan. Jika Menang-1 variabel mencapai 6 pertama maka Pemain 2 menang.

Saya mengerti bahwa solusi ini tidak scalable dengan mudah.

Komentar (0)

Ini adalah cara yang sangat sederhana untuk memeriksa.


    public class Game() { 

    Game player1 = new Game('x');
    Game player2 = new Game('o');

    char piece;

    Game(char piece) {
       this.piece = piece;
    }

public void checkWin(Game player) {

    // check horizontal win
    for (int i = 0; i 
Komentar (0)

Jika anda memiliki asrama bidang 5*5 untuk examle, saya menggunakan metode pemeriksaan:


public static boolean checkWin(char symb) {
  int SIZE = 5;

        for (int i = 0; i < SIZE-1; i++) {
            for (int j = 0; j 
Komentar (0)

Konstanta waktu O(8), rata-rata 4 pendek DAN's. Pemain = nomor pendek. Perlu pemeriksaan tambahan untuk memastikan langkah ini berlaku.


// O(8)
boolean isWinner(short X) {
    for (int i = 0; i < 8; i++)
        if ((X & winCombinations[i]) == winCombinations[i])
            return true;
    return false;
}

short[] winCombinations = new short[]{
  7, 7 
Komentar (1)