Home > Net >  JS Function for Hardcoded TicTacToe check for win with a function
JS Function for Hardcoded TicTacToe check for win with a function

Time:01-11

This time I am making a tictactoe game for my work in vanilla JS. I can get it to work by using if statements, but I now need it to work with an added function I am struggling to get working (which is a requirement). The code is what I have come up with so far.

This is my code:

const userGame = [
    row1 = ["O", "O", "O"],
    row2 = ["", "", ""],
    row3 = ["", "", ""]
]

// Made this for easier referencing
cells = [
    cell1 = row1[0],
    cell2 = row1[1],
    cell3 = row1[2],
    cell4 = row2[0],
    cell5 = row2[1], // C = Center
    cell6 = row2[2],
    cell7 = row3[0],
    cell8 = row3[1],
    cell9 = row3[2]
]

// Defining win conditions (row, column, diagonal)
const rowWinO = [
    ["O", "O", "O"]
]

const rowWinX = [
    ["X", "X", "X"]
]

const colWinO = [
    ["O"],
    ["O"],
    ["O"]
]

const colWinX = [
    ["X"],
    ["X"],
    ["X"]
]

const diagonalWinO = [
    ["", "", "O"],
    ["", "O", ""],
    ["O", "", ""]
]

const diagonalWinX = [
    ["", "", "X"],
    ["", "X", ""],
    ["X", "", ""]
]

const diagonalWinInverseO = [
    ["O", "", ""],
    ["", "O", ""],
    ["", "", "O"]
]

const diagonalWinInverseX = [
    ["X", "", ""],
    ["", "X", ""],
    ["", "", "X"]
]

// Placement of X and O
Xcell = 'X'
Ocell = 'O'
let gameWin = false

// Where the struggle is. 
// The function isn't calling (for example)
// rowWinO for the if statements below this function. 
// This program should be returning rowWinO and 
// declaring that 'O has won on a row'

function evaluatePlay(board) {
    board = userGame
    if (cell1 == Ocell && cell2 == Ocell && cell3 == Ocell
    || cell4 == Ocell && cell5 == Ocell && cell6 == Ocell
    || cell7 == Ocell && cell8 == Ocell && cell9 == Ocell) {
        rowWinO == true
    }

    else if (cell1 == Xcell && cell2 == Xcell && cell3 == Xcell
        || cell4 == Xcell && cell5 == Xcell && cell6 == Xcell
        || cell7 == Xcell && cell8 == Xcell && cell9 == Xcell) {
            rowWinX == true
        }

    else if (cell1 == Ocell && cell4 == Ocell && cell7 == Ocell
        || cell2 == Ocell && cell5 == Ocell && cell8 == Ocell
        || cell3 == Ocell && cell6 == Ocell && cell9 == Ocell) {
            colWinO == true
        }

    else if (cell1 == Xcell && cell4 == Xcell && cell7 == Xcell
        || cell2 == Xcell && cell5 == Xcell && cell8 == Xcell
        || cell3 == Xcell && cell6 == Xcell && cell9 == Xcell) {
            colWinX == true
        }

    else if (board == diagonalWinO ) {
        // Done this way because the board can only get
        // a win like this in one way
        diagonalWinO == true 
    }

    else if (board == diagonalWinInverseO) {
        diagonalWinInverseO == true
    }
    
    else if (board == diagonalWinX) {
        diagonalWinX == true
    }

    else if (board == diagonalWinInverseX) {
        diagonalWinInverseX == true
    }

    if (rowWinO == true || rowWinX == true || colWinO == true
        || colWinX == true || diagonalWinO == true || diagonalWinX == true
        || diagonalWinInverseO == true || diagonalWinInverseX == true) {
        // If the gameboard matches a win state, return that we have a 
        // winner
        gameWin == true
    }

    return;
}

evaluatePlay(userGame)

if (gameWin == true) {
    if (rowWinO == true ) {
        // O wins on a row
        console.log('O wins on a row!')
    }

    // X Wins on a row
    else if(rowWinX == true) {
        console.log('X wins on a row! ')
    }

    // O Wins on a column
    else if(colWinO == true) {
        console.log('O wins on a column!')
    }

    // X Wins on a column
    else if(colWinX == true) {
        console.log('X wins on a column!')
    }

    // O wins on a diagonal
    else if(diagonalWinO == true) {
        console.log('O wins on a diagonal!')
    }

    else if(diagonalWinInverseO == true) {
        console.log('O wins on a diagonal!')
    }

    // X wins on a diagonal
    else if(diagonalWinX == true) {
        console.log('X wins on a diagonal!')
    }

    else if(diagonalWinInverseX == true) {
        console.log('X wins on a diagnoal!')
    }
}

else if (gameWin == false) {
    console.log('Nothing happens')
}

I defined a game board of hard coded tic-tac-toe.

const userGame = [
    row1 = ["O", "O", "O"],
    row2 = ["", "", ""],
    row3 = ["", "", ""]
]

Because I have to check it against multiple variables I am sadly getting confused with other people's work as they define a winning state in a single array.

The program's goal is to compare this with the winning game states like winning on a row or diagonal. However instead of using an array to define all the win cons I have to pre-define these win cons for my work, like

const rowWinO = [ ["O", "O", "O"] ]

const diagonalWinX = [
    ["", "", "X"],
    ["", "X", ""],
    ["X", "", ""]
]

My issue is the function I have. It's long, so the gist of it is to check if the indexes of the original game array and compare it the game state. As you can see above the gameBoard wins on a row, so...

Expected Output

The function should recognise this and return true. If any win condition is met, then it should recognise the game has been won (gamewin == true). Using that, the below if statement should check if (rowWinO == true && gameWin == true) display the message ('X won on a row.')

Note the win conditions are nested in gameWin for the if statements

 else if <the game is not a winner> `console.log('Nothing happens')`

I have tried tweaking it by changing X = 'X' to Xcell = 'X' but I am honestly not sure what to change anymore.

The previous program worked with if statements like this:

else if(row1[0] == 'O' && row2[0] == 'O' && row3[0] == 'O') {
    console.log('O wins on column')
    gameWin == true
}

The program does not need to check for draws, only for wins.

CodePudding user response:

This solution takes a 2d game board but flattens it so it can operate in 1d.

Changes to play such as board size and longer sequences might change things so that instead it would be optimal to generate win conditions on the fly or to determine them algorithmically. However, there aren't enough win patterns to make that necessary under your conditions so we just match against the known patterns.

// map of win patterns
const wins = [
  '100100100', // verticals
  '010010010',
  '001001001',
  '111000000', // horizontals
  '000111000',
  '000000111',
  '100010001', // diagonals
  '001010100', 
  '000000000', // not a win pattern, but lets `checkGame` handle no-match
].map(w=>w.split('').map(c=>c=='1')); // convert strings to true/false arrays

const checkGame = game => {
  // flatten the 2d game to a 1d array
  game = game.flat();
  // who's winning
  let who;
  // check each win pattern against the game
  wins.some(win => {
    // clear `who`
    who = '';
    return win.every((c,i) => {
      // are we checking this cell?
      if (!c) return true;
      // yes; is this cell marked?
      if (!game[i]) return false;
      // yes; is this the first spot to check?
      if (!who) {
        // if so, track the marker in `who`
        who = game[i];
        return true;
      }
      // do the rest of the cells in this pattern have the same mark?
      if (who == game[i]) return true;
      // if not, match fails
      return false;
    });
  });
  return who;
};

// some tests
const O="O", X="X", _="";
const userGame1 = [
  [O, O, O],
  [_, _, _],
  [_, _, _]
];
const userGame2 = [
  [X, _, _],
  [X, _, _],
  [X, _, _]
];
const userGame3 = [
  [O, X, O],
  [X, O, X],
  [X, O, X]
];
const userGame4 = [
  [_, X, _],
  [_, X, O],
  [_, X, O]
];
const userGame5 = [
  [O, X, _],
  [O, X, _],
  [_, X, _]
];

console.log('1:',checkGame(userGame1));
console.log('2:',checkGame(userGame2));
console.log('3:',checkGame(userGame3));
console.log('4:',checkGame(userGame4));
console.log('5:',checkGame(userGame5));

  • Related