 <p>I think you are misunderstanding how to look ahead in a game like this. Do not 'total' the values returned by <code>evaluateLine</code>.</p> <p>Here is pseudocode for the minimax score of a tic-tac-toe board (what <code>evaluateBoard</code> should return). Note that <code>evaluateBoard</code> will need to have a notion of <code>currentTurn</code>.</p> <pre><code>function evaluateBoard(board, currentTurn) // check if the game has already ended: if WhiteHasWon then return -10 if BlackHasWon then return +10 // WhiteHasWon returns true if there exists one or more winning 3-in-a-row line for white. // (You will have to scan for all 8 possible 3-in-a-row lines of white pieces) // BlackHasWon returns true if there exists one or more winning 3-in-a-row line for black if no legal moves, return 0 // draw // The game isn't over yet, so look ahead: bestMove = notset resultScore = notset for each legal move i for currentTurn, nextBoard = board Apply move i to nextBoard score = evaluateBoard(nextBoard, NOT currentTurn).score if score is &lt;better for currentTurn&gt; than resultScore, then resultScore = score bestMove = move i return (resultScore, bestMove) </code></pre> <p>One very key difference between this and your version and my version is that my version is <strong>recursive</strong>. Yours only goes one level deep. Mine calls <code>evaluateBoard</code> from inside <code>evaluateBoard</code>, which would be an infinite loop if we aren't careful (once the board fills up, it can't go any deeper, so it's not actually infinite)</p> <p>Another difference is that yours totals stuff when it shouldn't. The resulting score from tic-tac-toe is -10,0, or 10 only once you've looked to the end of the game. You should be picking the best possible move available to that player at that time, and ignoring all other possibilities completely because you only care about the "best" line of play. The game score is equal to the result of optimal play.</p> <p>Expanding <code>&lt;better for currentTurn&gt;</code> is messy in minimax, which is why negamax is cleaner. White prefers low scores and black prefers high scores, so you need some if statements to make it choose the appropriate preferred score. You have this part already (at the end of your best move code), but it needs to be evaluated inside the recursion instead of just at the end.</p>