<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/tic-tac-toe-part-3-the-minimax-algorithm/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://r.prevos.net/tic-tac-toe-part-3-minimax-algorithm/"> The Devil is in the Data</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><a rel="nofollow" href="http://r.prevos.net/tic-tac-toe-war-games/wargames/" target="_blank"><img data-orig-file="https://i2.wp.com/r.prevos.net/wp-content/uploads/sites/11/2017/04/wargames.gif?resize=300%2C300" data-orig-size="600,600" data-medium-file="http://r.prevos.net/wp-content/uploads/sites/11/2017/04/wargames-300x300.gif" data-attachment-id="562" data-image-meta="{" data-image-description="" src="https://i2.wp.com/r.prevos.net/wp-content/uploads/sites/11/2017/04/wargames.gif?resize=300%2C300" data-permalink="http://r.prevos.net/tic-tac-toe-war-games/wargames/" data-large-file="https://i2.wp.com/r.prevos.net/wp-content/uploads/sites/11/2017/04/wargames.gif?resize=300%2C300" alt="Tic Tac Toe minimax alogrithm" data-image-title="Tic Tac Toe War Games" data-comments-opened="1" class="wp-image-562" data-recalc-dims="1"></a>In two previous posts, I presented code to teach R to play the trivial game of <a rel="nofollow" href="http://r.prevos.net/?s=tic+tac+toe&submit=Search" target="_blank">Tic Tac Toe</a>. I thought this was an unbeatable algorithm. Alas, a comment from Alberto shattered my pride as he was able to beat my code.</p>
<p>The reason for the demise of my code was that I didn’t implement a full minimax algorithm, but instead looked only two moves ahead. I thought the common strategy rules (start in the centre and occupy the corners) would make the program unbeatable. When I simulated the game by instructing the computer to play against itself, Alberto’s strategy never arose because the code forces the centre field. Alberto’s code shows that you need to look at least three moves ahead for a perfect game. He has been so kind to share his code and gave me permission to publish it.</p>
<p>Alberto recreated two functions, for completeness I have added the complete working code that merges his improvements with my earlier work. The first two functions are identical to the previous post. These functions draw the game board and process the human player’s move by waiting for a mouse click.</p>
<pre>
# Draw the game board
draw.board &lt;- function(game) {
    xo &lt;- c(&quot;X&quot;, &quot; &quot;, &quot;O&quot;) # Symbols
    par(mar = rep(1,4))
    plot.new()
    plot.window(xlim = c(0,30), ylim = c(0,30))
    abline(h = c(10, 20), col=&quot;darkgrey&quot;, lwd = 4)
    abline(v = c(10, 20), col=&quot;darkgrey&quot;, lwd = 4)
    text(rep(c(5, 15, 25), 3), c(rep(25, 3), rep(15,3), rep(5, 3)), xo[game + 2], cex = 4)
    # Identify location of any three in a row
    square &lt;- t(matrix(game, nrow = 3))
    hor &lt;- abs(rowSums(square))
    if (any(hor == 3)) 
        hor &lt;- (4 - which(hor == 3)) * 10 - 5 
    else 
        hor &lt;- 0
    ver &lt;- abs(colSums(square))
    if (any(ver == 3)) 
        ver &lt;- which(ver == 3) * 10 - 5 
    else
        ver &lt;- 0
    diag1 &lt;- sum(diag(square))
    diag2 &lt;- sum(diag(t(apply(square, 2, rev)))) 
    # Draw winning lines
    if (all(hor > 0)) 
        for (i in hor) lines(c(0, 30), rep(i, 2), lwd = 10, col=&quot;red&quot;)
    if (all(ver > 0)) 
        for (i in ver) lines(rep(i, 2), c(0, 30), lwd = 10, col=&quot;red&quot;)
    if (abs(diag1) == 3) 
        lines(c(2, 28), c(28, 2), lwd = 10, col = &quot;red&quot;)
    if (abs(diag2) == 3) 
        lines(c(2, 28), c(2, 28), lwd = 10, col = &quot;red&quot;)
}

# Human player enters a move
move.human &lt;- function(game) {
    text(4, 0, &quot;Click on screen to move&quot;, col = &quot;grey&quot;, cex=.7)
    empty &lt;- which(game == 0)
    move &lt;- 0
    while (!move %in% empty) {
        coords &lt;- locator(n = 1) # add lines
        coords$x &lt;- floor(abs(coords$x) / 10) + 1
        coords$y &lt;- floor(abs(coords$y) / 10) + 1
        move &lt;- coords$x + 3 * (3 - coords$y)
    }
    return (move)
}
</pre>
<p>Alberto rewrote the functions that analyse the board and determine the move of the computer. The ganador (Spanish for winning) function assesses the board condition by assigning -10 or + 10 for a winning game and 0 for any other situation.</p>
<pre>
ganador &lt;- function(juego, player) {
    game &lt;- matrix(juego, nrow = 3, byrow = T)
    hor &lt;- rowSums(game)
    ver &lt;- colSums(game)
    diag &lt;- c(sum(diag(game)), sum(diag(apply(game, 1, rev))))
    if (-3 %in% c(hor, ver, diag))
        return(-10)
    if (3 %in% c(hor, ver, diag))
        return(10)
    else
        return(0)
}
</pre>
<p>The next function is the actual minimax algorithm. If the computer starts then the first move (<img alt="9!= 362880 " title="9!= 362880 " src="http://s0.wp.com/latex.php?latex=9%21%3D+362880+&bg=ffffff&fg=000&s=0" class="latex"> options to assess) takes a little while. The commented lines can be used to force a corner and make the games faster by forcing a random corner.</p>
<p>The minimax function returns a list with the move and its valuation through the ganador function. The function works recursively until it has filled the board and retains the best scoring move using the minimax method. To avoid the computer always playing the same move in the same situation random variables are added.</p>
<pre>
minimax &lt;- function(juego, player) {
    free &lt;- which(juego == 0)
    if(length(free) == 1) {
        juego[free] &lt;- player
        return(list(move = free, U = ganador(juego, player)))
    }
    poss.results &lt;- rep(0, 9)
    for(i in free) {
        game &lt;- juego
        game[i] &lt;- player
        poss.results[i] &lt;- ganador(game, player)
    }
    mm &lt;- ifelse(player == -1, &quot;which.min&quot;, &quot;which.max&quot;)
    if(any(poss.results == (player * 10))) {
        move &lt;- do.call(mm, list(poss.results))
        return(list(move = move, U = poss.results[move]))
    }
    for(i in free) {
        game &lt;- juego
        game[i] &lt;- player
        poss.results[i] &lt;- minimax(game, -player)$U
    }
    random &lt;- runif(9, 0, 0.1)
    poss.results[-free] &lt;- 100 * -player
    poss.results &lt;- poss.results + (player * random)
    move &lt;- do.call(mm, list(poss.results))
    return(list(move = move, U = poss.results[move]))
}
</pre>
<p>This final function stitches everything together and lets you play the game. Simply paste all functions in your R console and run them to play a game. The tic.tac.toe function can take two parameters, “human” and/or “computer”. The order of the parameters determines who starts the game.</p>
<pre>
# Main game engine
tic.tac.toe &lt;- function(player1 = &quot;human&quot;, player2 = &quot;computer&quot;) {
    game &lt;- rep(0, 9) # Empty board
    winner &lt;- FALSE # Define winner
    player &lt;- 1 # First player
    players &lt;- c(player1, player2)
    draw.board(game)
    while (0 %in% game &amp; !winner) { # Keep playing until win or full board
        if (players[(player + 3) %% 3] == &quot;human&quot;) # Human player
            move &lt;- move.human(game)
        else { # Computer player
            move &lt;- minimax(game, player)
            move &lt;- move$move
            }
        game[move] &lt;- player # Change board
        draw.board(game)
        winner &lt;- max(eval.game(game, 1), abs(eval.game(game, -1))) == 6 # Winner, winner, chicken dinner?
        player &lt;- -player # Change player
    }
}

tic.tac.toe()
</pre>
<p>This is my last word on Tic Tac Toe but now that the minimax conundrum is solved I could start working on other similar games such as <a rel="nofollow" href="https://en.wikipedia.org/wiki/Connect_Four" target="_blank">Connect Four</a>, <a rel="nofollow" href="https://en.wikipedia.org/wiki/Draughts" target="_blank">Draughts</a> or even the royal game of <a rel="nofollow" href="https://en.wikipedia.org/wiki/Chess" target="_blank">Chess</a>.</p>
<p>The post <a rel="nofollow" href="http://r.prevos.net/tic-tac-toe-part-3-minimax-algorithm/" target="_blank">Tic Tac Toe Part 3: The Minimax Algorithm</a> appeared first on <a rel="nofollow" href="http://r.prevos.net/" target="_blank">The Devil is in the Data</a>.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://r.prevos.net/tic-tac-toe-part-3-minimax-algorithm/"> The Devil is in the Data</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...

	<img alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/NQQlQaJbZ6E" height="1"></a></div>