Package: xo
APythonCLI game and library forTic-tac-toe.The library is written in a modular way. Its overall design consists of 4 decoupled components:A Tic-tac-toe board data structure,xo.board.An arbiter for analyzing the state of a board,xo.arbiter.A game engine to implement and enforce the Tic-tac-toe game logic,xo.game.And finally, an AI for finding excellent moves,xo.ai.The board>>>fromxo.boardimportisempty,Board>>>board=Board.fromstring('..x.o')>>>print(board)..x.o....>>>print(board.toascii())||x---+---+---|o|---+---+---||>>>board[1,3]x>>>board[3,3]='x'>>>print(board)..x.o...x>>>forr,c,pieceinboard:...ifisempty(piece):...print('{},{}'.format(r,c))...1,11,22,12,33,13,2The board isn’t concerned with whether or not a given layout can be reached in an actual Tic-tac-toe game. Hence, the following is perfectly legal:>>>board=Board.fromstring('xxxxxxxxo')>>>print(board)xxxxxxxxoThe arbiter is concerned about that though and can detect such invalid board layouts.The arbiter>>>fromxoimportarbiter>>>fromxo.boardimportBoard>>>arbiter.outcome(Board.fromstring(),'x'){'piece_counts':{'os':0,'xs':0,'es':9},'status':'in-progress'}>>>arbiter.outcome(Board.fromstring('xxxoo'),'o'){'piece_counts':{'os':2,'xs':3,'es':4},'details':[{'index':1,'positions':[(1,1),(1,2),(1,3)],'where':'row'}],'status':'gameover','reason':'loser'}>>>arbiter.outcome(Board.fromstring('xxxxxxxxo'),'x'){'piece_counts':{'os':1,'xs':8,'es':0},'status':'invalid','reason':'too-many-moves-ahead'}The game engineEnforcer of the game rules.>>>fromxo.gameimportGame>>>game=Game()>>>game.start('x')>>>game.moveto(1,1){'name':'next-turn','last_move':{'token':'x','r':1,'c':1}}>>>game.moveto(1,1){'name':'invalid-move','reason':'occupied'}>>>game.moveto(0,0){'name':'invalid-move','reason':'out-of-bounds'}>>>game.moveto(2,2){'name':'next-turn','last_move':{'token':'o','r':2,'c':2}}>>>game.moveto(3,1){'name':'next-turn','last_move':{'token':'x','r':3,'c':1}}>>>print(game.board.toascii())x||---+---+---|o|---+---+---x||>>>game.moveto(3,3){'name':'next-turn','last_move':{'token':'o','r':3,'c':3}}>>>game.moveto(2,1){'name':'gameover','reason':'winner','last_move':{'token':'x','r':2,'c':1},'details':[{'index':1,'positions':[(1,1),(2,1),(3,1)],'where':'column'}]}>>>game.moveto(1,3)...xo.error.IllegalStateError:gameover>>># start a new game>>>game.restart()>>># since x won, it would be x's turn to play>>># if the game was squashed then it would have been o's turn to play>>>game.moveto(1,1)>>>print(game.board.toascii())x||---+---+---||---+---+---||The AINo Tic-tac-toe library is complete without an AI that can play a perfect game of Tic-tac-toe.>>>fromxoimportai>>>fromxo.boardimportBoard>>>ai.evaluate(Board.fromstring('xo.xo.'),'x')MinimaxResult(score=26,depth=1,positions=[(3,1)])>>>ai.evaluate(Board.fromstring('xo.xo.'),'o')MinimaxResult(score=26,depth=1,positions=[(3,2)])>>>ai.evaluate(Board.fromstring('x.o'),'x')MinimaxResult(score=18,depth=5,positions=[(2,1),(3,1),(3,3)])Finally,xo.clibrings it all together in its implementation of the command-line Tic-tac-toe game. It’s interesting to see how easy it becomes to implement the game so be sure to check it out.Note:An extensive suite of tests is also available that can help you better understand how each component is supposed to work.InstallationInstall it using:$pipinstallxoYou would now have access to an executable calledxo. Type$xoto starting playing immediately.UsageFor help, type$xo-hBy defaultxois configured for a human player to play withxand a computer player to play witho. However, this can be easily changed to allow any of the other 3 possibilities:$# Computer vs Human$xo-xcomputer-ohuman$# Human vs Human$xo-xhuman-ohuman$xo-ohuman# since x defaults to human$# Computer vs Computer$xo-xcomputer-ocomputer$xo-xcomputer# since o defaults to computerYou can also change who plays first. By default it’s thexplayer.$# Let o play first$xo-foFinally, when letting the computers battle it out you can specify the number of times you want them to play each other. By default they play 50 rounds.$xo-xcomputer-r5.....Gamestatistics---------------Totalgamesplayed:5(2.438secs)Numberoftimesxwon:0Numberoftimesowon:0Numberofsquashedgames:5DevelopmentGet the source code.$gitclonegit@github.com:dwayne/xo-python.gitCreate avirtual environmentand activate it.$cdxo-python$pyvenvvenv$.venv/bin/activateThen, upgradepipandsetuptoolsand install the development dependencies.(venv)$pipinstall-Upipsetuptools(venv)$pipinstall-rrequirements-dev.txtYou’re now all set to begin development.TestingTests are written using theunittestunit testing framework.Run all tests.(venv)$python-munittestRun a specific test module.(venv)$python-munittesttests.test_arbiterRun a specific test case.(venv)$python-munittesttests.test_arbiter.GameoverPositionsTestCaseRun a specific test method.(venv)$python-munittesttests.test_arbiter.GameoverPositionsTestCase.test_when_x_winsCreditsThanks toPatrick Henry Winstonfor clarifying the Minimax algorithm. Hisvideoon the topic was a joy to watch.CopyrightCopyright (c) 2016 Dwayne Crooks. SeeLICENSEfor further details.Change Log1.0.0(2016-09-09)AddedA board data structureAn arbiterA game engineAn AI based on the Minimax algorithmA CLI0.0.1 (2016-09-05)Birth!