Writing this write up took considerably longer than actually writing the code.
I saw a post once commenting how the world doesn’t need another version of Tic-Tac-Toe made in Python. Well that’s too bad, because here comes another one! I keep telling myself I want to make a slightly more detailed run through some of my code writing, just for the sake of “This is the process,” so let’s see if I can make a go of it for this round. Funny enough, this isn’t the first time I’ve set out to make TicTacToe on my own accord, I once started working out doing it in C++ once, mostly because I wanted to see if I could build a super tough algorithm for a computer AI playing TicTacToe.
This whole post will contain a whole lot of somewhat repetitious and incremental Python code, but maybe it will be helpful to some newbie coders to get a better idea of how to step through what you’re writing and how to break up and plan different parts of your code.
The first step here, is to decide which method to use to create this little game. I could do it with Text but that feels ugly and boring. I could probably make a web version with Flask, but that feels overly complicated. That leaves Tkinter or Turtle. I opted for Turtle. I like Turtle, it has a fun sort of retro feel to it, and it’s simple enough to use.
This post is Extremely Long and full of code, so I’m putting ti behind a Read More, and here it is!
—– Read More —–: 100 Days of Python, Project 083 – Tic-Tac-Toe #100DaysofCodeBack when doing previous lessons, I build several basic skeleton versions of several of the projects we used, so I started with my “Basic Turtle” code.
from turtle import Turtle, Screen
screen = Screen()
screen.setup(width=600, height=600)
screen.exitonclick()
This code pretty much just draws a blank 600×600 pixel window that stays open until it’s clicked.
I also knew I would need to be able to draw some circles, so I pulled in and stripped a bit of my Spiro-graph code and made sure that it would open a window, and then draw a circle.
import turtle
from turtle import Turtle, Screen
screen = Screen()
screen.setup(width=600, height=600)
turt = Turtle()
turt.hideturtle()
turt.speed(500)
# Draws the Circle
turt.circle(75,360)
screen.exitonclick()
The end result being a nice circle on a blank screen. Later I’ll need to make it draw some X shapes as well, and draw them in different places, but for now, a basic circle is fine.
There isn’t much point in drawing circles or X shapes, without the board, so next step is to make the board. In case I need to redraw the board from scratch later, which I might, I’m going to break this out into a function called…. “draw_board”.
def draw_board(turt):
turt.penup()
turt.goto(100,225)
turt.pendown()
turt.goto(100,-225)
turt.penup()
turt.goto(-100,225)
turt.pendown()
turt.goto(-100,-225)
turt.penup()
turt.goto(225,100)
turt.pendown()
turt.goto(-225,100)
turt.penup()
turt.goto(225,-100)
turt.pendown()
turt.goto(-225,-100)
You’ll notice the penup() and pendown() calls. This is to keep the pen from drawing when it’s not supposed to. The way Turtle works, it’s essentially drawing, like with a plotter. Now, there is probably a slick way to draw this with less lines of codes using a loop or something, but I prefer to go for readability over “clever tricks” most of the time.
Based on the dimensions of 600×600, I can estimate where to place the lines. Turtle uses 0,0 as the center of the window. If I were to cut the window straight up into thirds, all the lines would land at +-100 and go from +300 to -300. I want the board to be a bit smaller as later I’ll add a title and maybe a score and some buttons and instructions at the bottom. The above code looks a little off center, so I played with the numbers a bit and came up with 75 instead of 100, for a nice balance. This goes in the code and is called after it’s created to draw the board, then a random circle, because the circle currently just draws from the last position of the drawing.
import turtle
from turtle import Turtle, Screen
screen = Screen()
screen.setup(width=600, height=600)
turt = Turtle()
turt.hideturtle()
turt.speed(500)
def draw_board(turt):
turt.penup()
turt.goto(75,225)
turt.pendown()
turt.goto(75,-225)
turt.penup()
turt.goto(-75,225)
turt.pendown()
turt.goto(-75,-225)
turt.penup()
turt.goto(225,75)
turt.pendown()
turt.goto(-225,75)
turt.penup()
turt.goto(225,-75)
turt.pendown()
turt.goto(-225,-75)
draw_board(turt)
turt.circle(60,360)
screen.exitonclick()
So why not fix that circle?
This is where some planning needs to be done. The simple way to do this is by setting up two functions, one to draw a circle, and one to draw an X. Then call that function with coordinates where to draw each shape. I’ll also have to pass the turtle, so it can do the drawing. X and O start at different places so each will need a set of starting coordinates to call later. I’m calling these x_coords and o_coords. Like the lines, this will take some trial and error to get them lined up properly. I’ll start with the O coordinates, because I already have the circle set up to draw. It’s also easier to draw a circle than an X, because Turtle has a built in command for it.
The planning comes from how to handle moves later. The easiest way will be to have a list that is 9 entries long, that will track which squares are occupied. The same index can be used on each list for the starting coordinates. In simpler terms, say the upper left box is “Box 0”. If the player selects “0” then it’s simple enough to pass “0” as the index to mark item “0” as used, then pass the coords of index “0”. I can also easily check the played list at index 0 to see if it already contains an X or an O. It also should be fairly easy to check win conditions on this list, but I’ll get to that later.
For starters, the list of o_coords just gets one entry, at the center. The board set up gives squares that are 150 pixels each side, so the Circles need to be slightly smaller. This makes it easy to calculate the first starting point, it’s in the center, so the X is 0, and it’s down slightly, at 60, which gives a circle 120 Pixels around. Which looks fine.
import turtle
from turtle import Turtle, Screen
x_coords = [[]]
o_coords = [[0,-60]]
screen = Screen()
screen.setup(width=600, height=600)
turt = Turtle()
turt.hideturtle()
turt.speed(500)
def draw_board(turt):
((( Code Removed for blog readiblity)))
## Draws a circle at specific coordinates
def draw_circle(turt,coords):
turt.penup()
turt.goto(coords[0],coords[1])
turt.pendown()
turt.circle(60,360)
draw_board(turt)
draw_circle(turt,o_coords[0])
screen.exitonclick()
Now it’s time to do the rest of the circles. Which are a bit more trial and error. I’ll reduce the code a but for readability, but basically, the draw_circle function call gets put in a for loop for each of o_coords. So the end result will be the TicTacToe board with all 9 circles. This won’t be in the final product, but it allows for quick testing. It’s easiest to break this down into seperate columns, so everything in a side columns gets drawn way off screen at 5550×5550, just because it was easy to tap “5” a bunch. The top and bottom get drawn and adjusted. Keep in mind, the circle command draws “from the bottom” so the coordinates are not centers.
o_coords = [[5550,5550],[0,100],[5550,55505],[5550,5550],[0,-60],[5550,5550],[5550,5550],[0,-100],[5550,0]]
def draw_circle(turt,coords):
turt.penup()
turt.goto(coords[0],coords[1])
turt.pendown()
turt.circle(60,360)
draw_board(turt)
for each in o_coords:
draw_circle(turt,each)
Once the Y Coordinates are worked out, all of the remaining rows can be aligned from their 5550 positions.
o_coords = [[5550,100],[0,100],[5550,100],[5550,-60],[0,-60],[5550,-60],[5550,-60],[0,-220],[5550,-60]]
And they get adjusted until all the circles look nicely aligned on the board.
import turtle
from turtle import Turtle, Screen
x_coords = [[]]
o_coords = [[-150,100],[0,100],[150,100],[-150,-60],[0,-60],[150,-60],[-150,-220],[0,-220],[150,-220]]
screen = Screen()
screen.setup(width=600, height=600)
turt = Turtle()
turt.hideturtle()
turt.speed(500)
def draw_board(turt):
turt.penup()
turt.goto(75,225)
turt.pendown()
turt.goto(75,-225)
turt.penup()
turt.goto(-75,225)
turt.pendown()
turt.goto(-75,-225)
turt.penup()
turt.goto(225,75)
turt.pendown()
turt.goto(-225,75)
turt.penup()
turt.goto(225,-75)
turt.pendown()
turt.goto(-225,-75)
def draw_circle(turt,coords):
turt.penup()
turt.goto(coords[0],coords[1])
turt.pendown()
turt.circle(60,360)
draw_board(turt)
for each in o_coords:
draw_circle(turt,each)
screen.exitonclick()
The next step is to do pretty much the same process for the X shapes. Though I’ll also have to set up how to draw the X shape first, so I can figure out where the start is. Which leads to a bit of adjustment and change of plan, which is not uncommon. I don’t need a second set of coordinates, I can use the same coordinates, and slide over to the start within the drawing function. I set up an initial batch of X shapes, only to find I had lines going everywhere. The “Left and Right” functions turn based on the last orientation. So I’d need to realign the turtle at the end of each call. After some futzing, I had a good set of X shapes going, one for each square.
import turtle
from turtle import Turtle, Screen
coords = [[-150,100],[0,100],[150,100],[-150,-60],[0,-60],[150,-60],[-150,-220],[0,-220],[150,-220]]
screen = Screen()
screen.setup(width=600, height=600)
turt = Turtle()
turt.hideturtle()
turt.speed(500)
def draw_board(turt):
turt.penup()
turt.goto(75,225)
turt.pendown()
turt.goto(75,-225)
turt.penup()
turt.goto(-75,225)
turt.pendown()
turt.goto(-75,-225)
turt.penup()
turt.goto(225,75)
turt.pendown()
turt.goto(-225,75)
turt.penup()
turt.goto(225,-75)
turt.pendown()
turt.goto(-225,-75)
def draw_circle(turt,coords):
turt.penup()
turt.goto(coords[0],coords[1])
turt.pendown()
turt.circle(60,360)
def draw_exe(turt,coords):
turt.penup()
turt.goto(coords[0]+50,coords[1])
turt.pendown()
turt.right(225)
turt.forward(144)
turt.penup()
turt.goto(coords[0]-50,coords[1])
turt.pendown()
turt.right(90)
turt.forward(144)
turt.left(315)
draw_board(turt)
# for each in coords:
# draw_circle(turt,each)
for each in coords:
draw_exe(turt,each)
screen.exitonclick()
So, now is where things get complicated, or at least, new, and interesting. How to make moves. There are certainly a variety of ways to accomplish this. The simple way would be “pick a number” as input. The fun and “Gamey” way would be, click inside the square you want. I want to preface this a bit, give the nature of why I am writing this out so explicitly. I’ve never done this before, nor am i sure you can even DO IT with Turtle and Screen. I would kind of assume so, given how it’s a GUI from a programming language designed in an age of windows based computing.
So where to start? How about search, “python turtle clickable portions of screen”, and see what comes up? It brings this page as a result, which seems promising. But I’ve never done this before, I’d rather not screw up my code, so it’s time to throw out a little side project to practice and get the hang of it. The site includes a basic version of what I’m going to need, so I’ll try that.
from turtle import *
import turtle as tur
def getPosition(i,j):
print("(", i, "," ,j,")")
return
def mainscr():
tur.onclick(getPosition)
tur.mainloop()
mainscr()
Aaaaand that code did nothing. It seems to be for an older version of Python as well. I modified the print part to simply read “Clicked” and it was still no go. But I have a direction now. Searching a bit with “Python Onclick get position” brings me to a Stack Exchange page, which mentions “onscreenclick
“. So I’ll modify the test code again.
And this works!
from turtle import *
import turtle as tur
def getPosition(i,j):
print("clicked")
print(f"({i},{j})")
return
def mainscr():
tur.onscreenclick(getPosition)
tur.mainloop()
mainscr()
clicked
(-58.0,80.0)
clicked
(-135.0,131.0)
clicked
(191.0,107.0)
And that’s how coding works in practice. I needed to figure something out, so I built a sandbox aside, and figured it out. I can also pretty much drop this code into my main program to use to find clicks.
Which brings me to the clicks.
So, I have a rough Idea of how large the squares are after setting up the board above. It’s 450 pixels in a square, each square is 150 pixels on a side. Now, I can string up a bunch of if statements, using the coordinates, from the click,
if i < 225 and i > 75 and j < 225 and j > 75:
return 2 ## square two, or top right
But that’s kind of… really sloppy. So maybe it’s time to rethink my code a bit to be more efficient. I’m working with a simple 3×3 grid. I probably SHOULD be managing my data in 2 dimensional matrices. I’m not looping through my coordinates anymore to test the X and O placements so let’s reformat that to be a 2 dimensional matrix. I’m also going to start with 0,0 as the Bottom Left square (I’ll get there). I’m also going to create a second array to manage which squares are played and thus ultimately score. So now the top fo the code looks like this.
import turtle from turtle import * from random import randint, choice coords = [[[-150,-220],[0,-220],[150,-220]], [[-150,-60],[0,-60],[150,-60]], [[[-150,100],[0,100],[150,100]]] played = [[False,False,False], [False,False,False], [False,False,False]]
Now, I also may want to reset the board later quickly, so let’s redefine the “played” array to make that more easily doable later.
def reset_board():
return [[False,False,False],
[False,False,False],
[False,False,False]]
coords = [[[-150,-220],[0,-220],[150,-220]],
[[-150,-60],[0,-60],[150,-60]],
[[-150,100],[0,100],[150,100]]]
played = reset_board()
This way later, to start a new game, I can just do “played = reset_board()”. In fact, there is a good chance that later I’ll just slap that inside of the game loop, but for now, I’ll leave it at the top. Back to the “check_position” function, which is a rebranded version of the previous “getPosition()”
def check_position(i,j):
print(f"({i},{j})")
This will handle what happens when the screen is clicked. Later there will be conditions for New Game and quit, but for now, it’s just going to be clicking squares.
So let’s talk a bit of math. I now have a 3×3 array of elements of coordinates to start drawing from. I also have a 3×3 array of score. What’s a good way to manage my click data. How about, transforming it, into coordinates for a 3×3 array, with 0,0 and 3,3 being the max. But how? Well, I know that my board is 450×450, centered around 0,0. So all clicks will be between -225 and +225. I need coordinates between 0 and 2, so I want everything to be positive, so when I check i and j, So all my coordinates need to be shifted by 225.
def check_position(i,j):
print(f"({(i+225)},{(y+225)})")
Ok, but they are still huge. BUT, I know my board is 450×450, and each column is a third of that at 150 pixels. So it’s a simple matter of dividing these shifted values by 450 each.
def check_position(i,j):
print(f"{int((i+225)/150)},{int((j+225)/150)}")
Now, when clicked, I get back “0,0”, “2,1”, “2,2” etc. I can now pass this along to one of my draw functions. The first step of course is to test it. I’m also going to add a quick if statement because I only want values between 225 and -225. My new function looks like this
def check_position(i,j):
if abs(i) < 225 and abs(j) <225:
# print(f"{int((i+225)/150)},{int((j+225)/150)}")
draw_circle(coords[int((i+225)/150)][int((j+225)/150)])
return
And clicking the grid draw circles!
And they are in the wrong places. Seems I’ve gotten my x and y coordinates flipped. Thankfully, this is easy to fix, i can just flip my i and j in my function call. Let’s check in on the current complete code.
import turtle from turtle import * def reset_board(): return [[False, False, False], [False, False, False], [False, False, False]] coords = [[[-150,-220],[0,-220],[150,-220]], [[-150,-60],[0,-60],[150,-60]], [[-150,100],[0,100],[150,100]]] played = reset_board() screen = Screen() screen.setup(width=600, height=600) turt = Turtle() turt.hideturtle() turt.speed(500) def draw_board(turt): turt.penup() turt.goto(75,225) turt.pendown() turt.goto(75,-225) turt.penup() turt.goto(-75,225) turt.pendown() turt.goto(-75,-225) turt.penup() turt.goto(225,75) turt.pendown() turt.goto(-225,75) turt.penup() turt.goto(225,-75) turt.pendown() turt.goto(-225,-75) def draw_circle(coords): turt.penup() turt.goto(coords[0],coords[1]) turt.pendown() turt.circle(60,360) def draw_exe(coords): turt.penup() turt.goto(coords[0]+50,coords[1]) turt.pendown() turt.right(225) turt.forward(144) turt.penup() turt.goto(coords[0]-50,coords[1]) turt.pendown() turt.right(90) turt.forward(144) turt.left(315) def check_position(j,i): if abs(i) < 225 and abs(j) <225: # print(f"{int((i+225)/150)},{int((j+225)/150)}") draw_circle(coords[int((i+225)/150)][int((j+225)/150)]) return draw_board(turt) def mainscr(): turtle.onscreenclick(check_position) turtle.mainloop() mainscr() screen.exitonclick()
Now clicking anywhere draws a circle. Getting close now! Still a ways to go. For starters, the computer doesn’t play. Also, it would be nice it players could not play in the same square twice. The latter is easy to fix with a little modification to check_position().
def check_position(j,i):
if abs(i) < 225 and abs(j) <225:
# print(f"{int((i+225)/150)},{int((j+225)/150)}")
x_point = int((i+225)/150)
y_point = int((j+225)/150)
if not played[x_point][y_point]:
draw_circle(coords[x_point][y_point])
played[x_point][y_point] = True
return
For now, the computer will just be dumb and play at random, so I’ll need to add a new import at the top.
import turtle
from turtle import *
from random import randint
I will also need a toggle to know who is currently playing, the user or the computer. I can make it just a straight bool value set to True and add an if statement, so if it’s the Player turn, then the click works, otherwise, the computer will choose two random numbers between -255 and 255 for each coordinate, and play them. More strategy could be added later fro the computer player, but getting it to randomly play is a good basic start since any level of strategy, would have “play randomly” as a baseline case.
Both of these need to be done together more or less. The computer can’t play without someone to play against and the player can’t play if the computer isn’t capable of taking a turn. So I’ll add both of these features at once.
This resulted in a new bug. The bool value toggle for X and O worked fine, but the computer wasn’t playing. It turns out that
turtle.onscreenclick
Doesn’t “exit”. So after quite a lot of testing with return statements and breaks, and even a lot of research, which didn’t really go anywhere, I found that I needed to call mainscr() again, after the Turtle Click did it’s thing.
import turtle
from turtle import *
from random import randint
from time import sleep
def reset_board():
return [[False, False, False],
[False, False, False],
[False, False, False]]
coords = [[[-150,-220],[0,-220],[150,-220]],
[[-150,-60],[0,-60],[150,-60]],
[[-150,100],[0,100],[150,100]]]
played = reset_board()
turn = True
rounds = 0
screen = Screen()
screen.setup(width=600, height=600)
turt = Turtle()
turt.hideturtle()
turt.speed(500)
def draw_board(turt):
turt.penup()
turt.goto(75,225)
turt.pendown()
turt.goto(75,-225)
turt.penup()
turt.goto(-75,225)
turt.pendown()
turt.goto(-75,-225)
turt.penup()
turt.goto(225,75)
turt.pendown()
turt.goto(-225,75)
turt.penup()
turt.goto(225,-75)
turt.pendown()
turt.goto(-225,-75)
turt.penup()
turt.goto(120,-275)
turt.pendown()
turt.write('EXIT', move=False, align='left', font = ('Arial', 20, 'normal'))
turt.penup()
def draw_circle(coords):
turt.penup()
turt.goto(coords[0],coords[1])
turt.pendown()
turt.circle(60,360)
def draw_exe(coords):
turt.penup()
turt.goto(coords[0]+50,coords[1])
turt.pendown()
turt.right(225)
turt.forward(144)
turt.penup()
turt.goto(coords[0]-50,coords[1])
turt.pendown()
turt.right(90)
turt.forward(144)
turt.left(315)
def check_position(j,i):
global turn
global rounds
if j > 120 and j < 180 and i < -250 and i > -275:
quit()
if abs(i) < 225 and abs(j) <225:
# print(f"{int((i+225)/150)},{int((j+225)/150)}")
x_point = int((i+225)/150)
y_point = int((j+225)/150)
if not played[x_point][y_point]:
if turn:
draw_circle(coords[x_point][y_point])
else:
draw_exe(coords[x_point][y_point])
played[x_point][y_point] = True
turn = not turn
rounds += 1
mainscr()
draw_board(turt)
def mainscr():
if rounds < 9:
if turn:
print("Player Turn")
turtle.onscreenclick(check_position)
else:
print("Computer Turn")
#turtle.onscreenclick(check_position)
sleep(1)
check_position(randint(-224,224),randint(-224,224))
else:
print("Game Over")
turtle.mainloop()
mainscr()
screen.exitonclick()
Keen eyed observers may notice this code also contains a few extra steps. I added an “Exit” button, because in testing, I wanted a cleaner way to dump out besides just hitting the “X”. This is accomplished inside the onscreenclick() function. First thing it does it check if the click was within the confines of the word “Exit”.
I also found that the PC had no way to stop playing if the board was filled, so I added a counter to check how many turns had been played.
The last major need here is of course, to check for a win condition. This requires a bit of adjustment to how the board check is being handled. Right now, it just toggles played squares to “True”. Instead, it needs to track which player played in each square, in order to check each round if someone has won. Fortunately, my check statement is “if not played[x_point][y_point]”, or “If not False”. Any other value will evaluate to True, so I can just adjust the code to assign an X or an O instead of a generic “True”
if not played[x_point][y_point]:
if turn:
draw_circle(coords[x_point][y_point])
played[x_point][y_point] = "O"
else:
draw_exe(coords[x_point][y_point])
played[x_point][y_point] = "X"
turn = not turn
So let’s go about checking for a win condition. This is going to get called a lot, so it’s getting it’s own function.
def check_win(board):
# check rows
for each in board:
if each.count("X") == 3 or each.count("O") == 3:
return each[0]
for i in range(0,3):
if board[0][i] == board[1][i] and board[0][i] == board[2][i]:
return board[0][i]
if board[0][0] == board[1][1] and board[1][1] == board[2][2]:
return board[0][0]
if board[0][2] == board[1][1] and board[1][1] == board[2][0]:
return board[0][2]
return False
I’ll admit, there may be a simpler way to accomplish this, but this will check each column, then each row and then the diagonals, and return either the winner, or “False”. This gets check in the main loop each run.
winner = check_win(played)
if winner:
print(f"{winner} has won the game!")
rounds = 20
Setting rounds to an arbitrarily large number like 20 breaks the play loop since the play loop looks for 9 or less.
At the basic level, this completes the game, but it still needs some quality of life features. A way to reset the game would be nice. It also could use a title at the top. All of these are just going to be text displays so they can be thrown in with the draw_board function. But they still need to do something, so some additional cases will need to be added to the check_clicked() function.
Adding these wraps up the complete game code. It certainly could use some touch ups and probably a good refactoring but for now, I’m satisfied enough because I’ve been working on this post for a while now. Below is the finished up code for the complete game.
import turtle
from turtle import *
from random import randint
from time import sleep
def reset_board():
return [[False, False, False],
[False, False, False],
[False, False, False]]
coords = [[[-150,-220],[0,-220],[150,-220]],
[[-150,-60],[0,-60],[150,-60]],
[[-150,100],[0,100],[150,100]]]
played = reset_board()
turn = True
rounds = 0
screen = Screen()
screen.setup(width=600, height=600)
turt = Turtle()
turt.hideturtle()
turt.speed(500)
def draw_board(turt):
turt.clear()
turt.penup()
turt.goto(75,225)
turt.pendown()
turt.goto(75,-225)
turt.penup()
turt.goto(-75,225)
turt.pendown()
turt.goto(-75,-225)
turt.penup()
turt.goto(225,75)
turt.pendown()
turt.goto(-225,75)
turt.penup()
turt.goto(225,-75)
turt.pendown()
turt.goto(-225,-75)
turt.penup()
turt.goto(120,-275)
turt.pendown()
turt.write('EXIT', move=False, align='left', font = ('Arial', 20, 'normal'))
turt.penup()
turt.goto(-220,-275)
turt.pendown()
turt.write('RESTART', move=False, align='left', font = ('Arial', 20, 'normal'))
turt.penup()
turt.goto(-150,240)
turt.pendown()
turt.write('TIC * TAC * TOE', move=False, align='left', font = ('Arial', 30, 'normal'))
turt.penup()
def restart_game():
global played
global turn
global rounds
played = reset_board()
turn = True
rounds = 0
draw_board(turt)
def draw_circle(coords):
turt.penup()
turt.goto(coords[0],coords[1])
turt.pendown()
turt.circle(60,360)
turt.penup()
def draw_exe(coords):
turt.penup()
turt.goto(coords[0]+50,coords[1])
turt.pendown()
turt.right(225)
turt.forward(144)
turt.penup()
turt.goto(coords[0]-50,coords[1])
turt.pendown()
turt.right(90)
turt.forward(144)
turt.left(315)
turt.penup()
def check_position(j,i):
global turn
global rounds
if j > 120 and j < 180 and i < -250 and i > -275:
quit()
if j > -220 and j < -100 and i < -250 and i > -275:
restart_game()
if abs(i) < 225 and abs(j) <225:
# print(f"{int((i+225)/150)},{int((j+225)/150)}")
x_point = int((i+225)/150)
y_point = int((j+225)/150)
if not played[x_point][y_point]:
if turn:
draw_circle(coords[x_point][y_point])
played[x_point][y_point] = "O"
else:
draw_exe(coords[x_point][y_point])
played[x_point][y_point] = "X"
turn = not turn
rounds += 1
mainscr()
def check_win(board):
# check rows
for each in board:
if each.count("X") == 3 or each.count("O") == 3:
return each[0]
for i in range(0,3):
if board[0][i] == board[1][i] and board[0][i] == board[2][i]:
return board[0][i]
if board[0][0] == board[1][1] and board[1][1] == board[2][2]:
return board[0][0]
if board[0][2] == board[1][1] and board[1][1] == board[2][0]:
return board[0][2]
return False
draw_board(turt)
def mainscr():
global rounds
global turn
winner = check_win(played)
if winner:
print(f"{winner} has won the game!")
rounds = 20
if rounds < 9:
if turn:
#print("Player Turn")
turtle.onscreenclick(check_position)
else:
#print("Computer Turn")
#turtle.onscreenclick(check_position)
sleep(1)
check_position(randint(-224,224),randint(-224,224))
else:
print("Game Over")
turtle.mainloop()
mainscr()
screen.exitonclick()
Josh Miller aka “Ramen Junkie”. I write about my various hobbies here. Mostly coding, photography, and music. Sometimes I just write about life in general. I also post sometimes about toy collecting and video games at Lameazoid.com.