Search code examples
algorithmluatic-tac-toelove2d

I'm having a bit of trouble making this tic-tac-toe algorithm work. It's an algorithm for checking if a move makes a win


This works really well with diagonals and the third row or third column. For some reason, when someone wins, either X or O, on the first and second row or columns, no win is signaled. Row and Col resemble the place where the play was made, and player resembles who did the play.

What's making my mind boggle is the fact that it doesn't recognize a win on all rows and columns, seems so weird to me that i'm just missing where the problem might be.

--[[
    Function that checks if there is a win whenever a play is made
]]

function checkWin(row, col, player)
    -- check rows. I have the row that the marker was placed. Go through it and see if there is a win.
    for c = 1, 3 do
        if board[row][c] ~= player then
            break
        end
        if c == 3 then
            gWhoWon = player
            gameOver = true
        end
    end


    -- check columns. I have the col that the marker was placed. Go through it and see if there is a win.
    for r = 1, 3 do
        if board[r][col] ~= player then
            break
        end
        if r == 3 then
            gWhoWon = player
            gameOver = true
        end
    end


    -- check diagonals. Check both diagonals and see if there is a win (can make this more efficient, only looking at 
    -- diagonals that matter).

    -- first diag
    for d = 1, 3 do
        if board[d][d] ~= player then
            break
        end
        if d == 3 then
            gWhoWon = player
            gameOver = true
        end
    end        

    -- anti diag
    for d = 1, 3 do
        if board[d][4-d] ~= player then
            break
        end
        if d == 3 then
            gWhoWon = player
            gameOver = true
        end
    end


    --[[
    if turn == 9 then
        gameOver = true
    end
    ]]
end

Here's the function in which I initialize my board and where I call the checkWin function:

function PlayState:init()
    xTurn = true
    gameOver = false
    turn = 1
    gWhoWon = ""

    -- board
    board = {
        {"", "", ""},
        {"", "", ""},
        {"", "", ""}
    }
end


function PlayState:update(dt)
    -- transition to win state when someone wins
    if gameOver then
        gStateMachine:change('win')
    end

    -- if there is a left mouse click, insert an "x" or an "o" on that square
    if love.mouse.wasPressed(1) then
        -- get mouse position
        x = love.mouse.getX()
        y = love.mouse.getY()
    
        -- iterate through the board
        for row = 1, 3 do
            for col = 1, 3 do
                -- if mouse click was inside a square and it is empty
                if isInsideSquare(x, y, row, col) and isEmpty(row, col) then
                    -- put an "x" on the square
                    if xTurn then
                        board[col][row] = 'x'
                        checkWin(row, col, 'x')  -- check if this move makes a win
                        xTurn = false
                    -- put an "o" on the square
                    else
                        board[col][row] = 'o'
                        checkWin(row, col, 'o')  -- check if this move makes a win
                        xTurn = true
                    end
                turn = turn + 1
                end
            end
        end
    end
end

Solution

  • There is a mix-up in using row and column values for the dimensions of the board matrix:

    • In the update method you have code like this: board[col][row] = 'x', so where the column is the first dimension of the matrix, but:

    • In the checkWin function, you have code like board[row][c] ~= player, so where the column is the second dimension of the matrix

    This will lead to unexpected results. Make sure to harmonise your code so that each of the two array dimensions are always used for the same axis (row versus column).