Hi friends, this little post follows the latest video I have just uploaded on youtube, about writing a noughts and crosses game (tic-tac-toe) in bash on Linux. Clearly, bash is not necessarily the best language for the job, and this is not the sort of thing I usually write. But a student challenged me to make noughts and crosses in bash, so I thought, why not :)
Watch the video:
A few more explanations: before starting to write the script, I looked at the few examples already available online. They pretty much all had certain characteristics in common, namely: the use of an array to represent the grid, and either a digit or a letter that was displayed in each cell of the array in order to indicate the position to play.
So I chose a different approach on principle. I « drew » a grid less ugly than most of the ones I found, which were hurting my eyes, and set about placing the Xs and Os in the cells using coordinates, as in battleship. Since the cells have no visible character in them by default, I initialise (empty) the grid’s cells by putting a space in them to keep the grid from becoming distorted. The result looks like this:

I made a whole pile of decisions « as I went » and of course there are dozens of ways to do this. For example, to check whether the position is already taken I look at whether it contains an O or an X, but I could very well simply check, for example, whether it contains anything other than the space I put there.

I used case several times instead of if / elif because, given the number of cells, I find the result much more readable. See:

I also remembered that, in the code examples I had just read, the eight winning conditions were not very readable as a series of “if” statements. So I moved them into a checkline() function, making the conditions for the eight positions much easier to write and check:

Note: I put the check_line function inside the check_victory function: there is no particular reason for this. It will work just as well outside; I simply took the opportunity to show that it was possible (even if it is only really useful in certain specific cases)
Finally, I hesitated a little when writing the main “game_start” function, probably because I wrote it last rather than first, so I had no clear idea beforehand of how to handle the sequence of turns.
One could use while, util, perhaps for, and use the turn count, incrementing it each time the loop runs. Another option was simply to spell out all 9 turns one by one (the least elegant approach, but probably the most reliable in operation).
However, since I had not used separate variables for the player and the O or X in the cells, I chose a compromise that spared me from changing one or more of the earlier functions:
I initialize the first turn at 1, and the PLAYER at X (in noughts and crosses, X generally always goes first). I did not implement player names, and reworking the functions would have taken more time, so I only enter the loop after playing the first turn and incrementing the turn count.

Then, until there is not a single empty cell left (each actually contains a space, as explained at the start), I alternate between O and X. I increment the turn count purely for display, but in practice the game works perfectly without it, since the loop never uses that count.
Once all the cells are filled (provided nobody has won earlier), then the game ends.
I put the script under the GPL license and it is available via the following link: 2b3ts.sh (Brain Bash Tic-Tac-Toe)
—
Christophe Casalegno
You can follow me on: Twitter | Facebook | Linkedin | Telegram | Youtube

Leave a comment
Add a comment