Pygame Tic Tak Toe Logic? How Would I Do It
I am trying to make a tic tak toe game with pygame and I was wondering how would I do the logic here is what I have so far. VIDEO < I only have it when I click on the middle button it will display the player 2 x on the screen and then the image that is hovering over my mouse will turn into O for player 1 turn to go BUT my question is how would I do the logic like if player 1 gets 3 in a row or player 2 gets 3 across in a row I am really confused on this and I need someone to walk me throw it
my tic tak toe game right now CODE
import pygame,random
pygame.init()
# draw our window
window = pygame.display.set_mode((500,540),pygame.NOFRAME)
pygame.display.set_caption("Tic Tac TOE")
MANUAL_CURSOR = pygame.image.load('nw.png').convert_alpha()
MANUAL_CURSOR2 = pygame.image.load('nOW.png').convert_alpha()
bg = pygame.image.load("ticO.png")
fps = 40
clock = pygame.time.Clock()
class button():
def __init__(self, color, x,y,width,height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
self.over = False
def draw(self,window,outline=None):
#Call this method to draw the button on the screen
if outline:
pygame.draw.rect(window, outline, (self.x-2,self.y-2,self.width+4,self.height+4),0)
pygame.draw.rect(window, self.color, (self.x,self.y,self.width,self.height),0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 60)
text = font.render(self.text, 1, (0,0,0))
window.blit(text, (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2)))
def isOver(self, pos):
#Pos is the mouse position or a tuple of (x,y) coordinates
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
return True
return False
def playSoundIfMouseIsOver(self, pos, sound):
if self.isOver(pos):
if not self.over:
beepsound.play()
self.over = True
else:
self.over = False
class particle:
def __init__(self,x):
self.x = x
self.partilight = pygame.image.load("noW.png")
def draw(self,window):
window.blit(self.partilight,(self.x))
white = (250,250,250)
greenbutton2 = button((0,255,0),190,215,100,100, '')
greenbutton3 = button((0,255,0),335,215,100,100, '')
greenbutton4 = button((0,255,0),70,215,100,100, '')
greenbutton5 = button((0,255,0),70,350,100,100, '')
greenbutton6 = button((0,255,0),190,350,100,100, '')
greenbutton7 = button((0,255,0),335,350,100,100, '')
greenbutton8 = button((0,255,0),70,90,100,100, '')
greenbutton9 = button((0,255,0),190,90,100,100, '')
greenbutton10 = button((0,255,0),335,90,100,100, '')
font = pygame.font.Font("fos.ttf", 60)
score = 1
cointext = font.render("" + str(score), True, (255,255,255))
coinrect = cointext.get_rect()
coinrect.center = ((100,50))
particles = []
pos = pygame.mouse.get_pos()
def redraw():
window.fill((174, 214, 241))
window.blit(bg,(0,0))
greenbutton2.draw(window)
greenbutton3.draw(window)
greenbutton4.draw(window)
greenbutton5.draw(window)
greenbutton6.draw(window)
greenbutton7.draw(window)
greenbutton8.draw(window)
greenbutton9.draw(window)
greenbutton10.draw(window)
for particle in particles:
particle.draw(window)
pos = pygame.mouse.get_pos()
if score >= 0:
window.blit(MANUAL_CURSOR, MANUAL_CURSOR.get_rect(center = pygame.mouse.get_pos()))
pygame.mouse.set_visible(False)
if score >= 1:
window.blit(MANUAL_CURSOR2, MANUAL_CURSOR2.get_rect(center = pygame.mouse.get_pos()))
if score >= 2:
window.blit(MANUAL_CURSOR, MANUAL_CURSOR.get_rect(center = pygame.mouse.get_pos()))
if score >= 3:
window.blit(MANUAL_CURSOR2, MANUAL_CURSOR2.get_rect(center = pygame.mouse.get_pos()))
if score >= 4:
window.blit(MANUAL_CURSOR, MANUAL_CURSOR.get_rect(center = pygame.mouse.get_pos()))
if score >= 5:
window.blit(MANUAL_CURSOR2, MANUAL_CURSOR2.get_rect(center = pygame.mouse.get_pos()))
if score >= 6:
window.blit(MANUAL_CURSOR, MANUAL_CURSOR.get_rect(center = pygame.mouse.get_pos()))
if score >= 7:
window.blit(MANUAL_CURSOR2, MANUAL_CURSOR2.get_rect(center = pygame.mouse.get_pos()))
if score >= 8:
window.blit(MANUAL_CURSOR, MANUAL_CURSOR.get_rect(center = pygame.mouse.get_pos()))
# our main loop
runninggame = True
while runninggame:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
runninggame = False
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
if greenbutton2.isOver(pos):
score += 1
cointext = font.render("" + str(score), True, (255,255,255))
coinrect.center = ((100,50))
for x in range(4):
particles.append(particle(MANUAL_CURSOR.get_rect(center = pygame.mouse.get_pos())))
redraw()
pygame.display.update()
pygame.quit()
the assets I am using Please! use so when your testing out the code
Solution 1:
Class names should normally use the CapWords convention. The name of the class should be Button
rather than button
. Instance Variables should be lowercase. Hence the name of an object of the typ Button
should be button
.
Furthermore use a pygame.Rect
object and collidepoint
. See How do I detect if the mouse is hovering over a button? PyGame button class is not displaying the text or changing colour on hover.
For Instance:
class Button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.rect = pygame.Rect(x, y, width, height)
self.text = text
self.over = False
def draw(self, window, outline=None):
pygame.draw.rect(window, self.color, self.rect)
if outline:
pygame.draw.rect(window, outline, self.rect.inflate(-4, -4), 3)
def isOver(self, pos):
return self.rect.collidepoint(pos)
Create a 3x3 grid of Buttons
and an 3x3 grid for the Particle
objects. The initial value of the particle grid is None
:
button_grid = [[Button((0, 128, 0), 70+i*120, 90+j*120, 100, 100, '') for i in range(3)] for j in range(3)]
particle_grid = [[None for i in range(3)] for j in range(3)]
Draw the grids in redraw
def redraw():
window.fill((32, 32, 32))
for i in range(len(button_grid)):
for j in range(len(button_grid[0])):
b = button_grid[i][j]
p = particle_grid[i][j]
is_over = p == None and b.isOver(pygame.mouse.get_pos())
b.draw(window, (255, 255, 255) if is_over else None)
if p:
p.draw(window)
The particle image ahs to be an argument of the constructor of the class Particle
. Add a method to the class to set the position:
class Particle:
def __init__(self, image):
self.pos = (0, 0)
self.image = image
def set_pos(self, pos):
self.pos = pos
def draw(self, window):
window.blit(self.image, self.image.get_rect(center = self.pos))
Create a method that creates a new particle dependent on the current turn:
def new_particle(turn):
image = MANUAL_CURSOR if turn % 2 == 0 else MANUAL_CURSOR2
return Particle(image)
Add a variable for the current turn and create an initial Particle
object:
turn = 0
particle = new_particle(turn)
Set the position of the Particle
object using the current mouse position and draw the object in the application loop:
runninggame = True
while runninggame:
# [...]
particle.set_pos(pygame.mouse.get_pos())
redraw()
particle.draw(window)
pygame.display.update()
When you click a field, check that the corresponding field in the particle grid is empty. Copy the center of the field to the position of the particle. Assign the particle to the grid. Increment the turn and create a new particle:
while runninggame:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
runninggame = False
if event.type == pygame.MOUSEBUTTONDOWN:
for i in range(len(button_grid)):
for j in range(len(button_grid[0])):
b = button_grid[i][j]
if b.isOver(event.pos) and particle_grid[i][j] == None:
particle.set_pos(b.rect.center)
particle_grid[i][j] = particle
turn += 1
particle = new_particle(turn)
Add a score for both players:
score1 = 0
score2 = 0
Add a function that evaluates whether there are 3 identical images in a row:
def has_won(pg):
pg = particle_grid
for i in range(3):
if pg[i][0] and pg[i][1] and pg[i][2]:
if pg[i][0].image == pg[i][1].image == pg[i][2].image:
return pg[i][0].image
for j in range(3):
if pg[0][j] and pg[1][j] and pg[2][j]:
if pg[0][j].image == pg[1][j].image == pg[2][j].image:
return pg[0][j].image
if pg[0][0] and pg[1][1] and pg[2][2]:
if pg[0][0].image == pg[1][1].image == pg[2][2].image:
return pg[0][0].image
if pg[0][2] and pg[1][1] and pg[2][0]:
if pg[0][2].image == pg[1][1].image == pg[2][0].image:
return pg[0][2].image
return None
Test to see if a player has won after clicking a button. When a player wins, increase the appropriate score and reset the particle grid:
while runninggame:
clock.tick(fps)
for event in pygame.event.get():
# [...]
if event.type == pygame.MOUSEBUTTONDOWN:
[...]
won = has_won(particle_grid)
if won:
if won == MANUAL_CURSOR:
score1 += 1
else:
score2 += 1
print(score1, score2)
particle_grid = [[None for i in range(3)] for j in range(3)]
Add a function that evaluates whether the grid is full:
def grid_is_full(pg):
return all(cell for row in pg for cell in row)
Clear the grid when it's full:
while runninggame:
clock.tick(fps)
for event in pygame.event.get():
# [...]
if event.type == pygame.MOUSEBUTTONDOWN:
[...]
if grid_is_full(particle_grid):
particle_grid = [[None for i in range(3)] for j in range(3)]
Minimal example:
import pygame,random
pygame.init()
class Button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.rect = pygame.Rect(x, y, width, height)
self.text = text
self.over = False
def draw(self, window, outline=None):
pygame.draw.rect(window, self.color, self.rect)
if outline:
pygame.draw.rect(window, outline, self.rect.inflate(-4, -4), 3)
def isOver(self, pos):
return self.rect.collidepoint(pos)
class Particle:
def __init__(self, image):
self.pos = (0, 0)
self.image = image
def set_pos(self, pos):
self.pos = pos
def draw(self, window):
window.blit(self.image, self.image.get_rect(center = self.pos))
def new_particle(turn):
image = MANUAL_CURSOR if turn % 2 == 0 else MANUAL_CURSOR2
return Particle(image)
def has_won(pg):
pg = particle_grid
for i in range(3):
if pg[i][0] and pg[i][1] and pg[i][2]:
if pg[i][0].image == pg[i][1].image == pg[i][2].image:
return pg[i][0].image
for j in range(3):
if pg[0][j] and pg[1][j] and pg[2][j]:
if pg[0][j].image == pg[1][j].image == pg[2][j].image:
return pg[0][j].image
if pg[0][0] and pg[1][1] and pg[2][2]:
if pg[0][0].image == pg[1][1].image == pg[2][2].image:
return pg[0][0].image
if pg[0][2] and pg[1][1] and pg[2][0]:
if pg[0][2].image == pg[1][1].image == pg[2][0].image:
return pg[0][2].image
return None
def grid_is_full(pg):
return all(cell for row in pg for cell in row)
def redraw():
window.fill((32, 32, 32))
for i in range(len(button_grid)):
for j in range(len(button_grid[0])):
b = button_grid[i][j]
p = particle_grid[i][j]
is_over = p == None and b.isOver(pygame.mouse.get_pos())
b.draw(window, (255, 255, 255) if is_over else None)
if p:
p.draw(window)
window = pygame.display.set_mode((500,540))
pygame.display.set_caption("Tic Tac TOE")
fps = 40
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 50)
#MANUAL_CURSOR = pygame.image.load('nw.png').convert_alpha()
#MANUAL_CURSOR2 = pygame.image.load('nOW.png').convert_alpha()
size = (60, 60)
MANUAL_CURSOR = pygame.Surface(size)
MANUAL_CURSOR.fill((127, 127, 127))
pygame.draw.line(MANUAL_CURSOR, (0, 127, 255), (5, 5), (size[0]-5, size[1]-5), 3)
pygame.draw.line(MANUAL_CURSOR, (0, 127, 255), (size[0]-5, 5), (5, size[1]-5), 3)
MANUAL_CURSOR2 = pygame.Surface(size)
MANUAL_CURSOR2.fill((127, 127, 127))
pygame.draw.circle(MANUAL_CURSOR2, (127, 0, 255), (size[0]//2, size[1]//2), size[0]//2-5, 3)
score1 = 0
score2 = 0
button_grid = [[Button((0, 128, 0), 70+i*120, 90+j*120, 100, 100, '') for i in range(3)] for j in range(3)]
particle_grid = [[None for i in range(3)] for j in range(3)]
turn = 0
particle = new_particle(turn)
runninggame = True
while runninggame:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
runninggame = False
if event.type == pygame.MOUSEBUTTONDOWN:
for i in range(len(button_grid)):
for j in range(len(button_grid[0])):
b = button_grid[i][j]
if b.isOver(event.pos) and particle_grid[i][j] == None:
particle.set_pos(b.rect.center)
particle_grid[i][j] = particle
turn += 1
particle = new_particle(turn)
won = has_won(particle_grid)
if won:
if won == MANUAL_CURSOR:
score1 += 1
else:
score2 += 1
print(score1, score2)
particle_grid = [[None for i in range(3)] for j in range(3)]
if grid_is_full(particle_grid):
particle_grid = [[None for i in range(3)] for j in range(3)]
particle.set_pos(pygame.mouse.get_pos())
scoreText1 = font.render("Player 1 Score: " + str(score1), True, (128, 0, 0))
scoreText2 = font.render("Player 2 Score: " + str(score2), True, (128, 0, 0))
redraw()
window.blit(scoreText1, (70, 30))
window.blit(scoreText2, (70, 460))
particle.draw(window)
pygame.display.update()
pygame.quit()
exit()