Search code examples
pythonpygametic-tac-toe

Why does the computer generates so many random places?


I am making a tic tac toe game, in which the player plays against the computer. The problem is that, I have programmed a rand() definition which is called only when there is no combination, eg. the player doesn't has 'X' on 1x1 and 1x2 or the player doesn't have 'X' on 1x3 and 1x2. Then computer generates a random box that has to be filled with 'O' but the computer fills all the leftover space except the 'X' box. I need that the computer fills up only one random space and then turns the player.turn to "player". Remember that I have not completed the computer.defend().

This is the picture:

enter image description here Here is my code:

import pygame,os,random #import


os.environ['SDL_VIDEO_CENTERED'] = '1' # You have to call this before pygame.init()

pygame.init() #initilization

###########creating screen#############
info = pygame.display.Info()
screen_width,screen_height = info.current_w,info.current_h
window_width,window_height = screen_width,screen_height-65

canvas = pygame.display.set_mode((window_width,window_height)) #setting the screen
##########loading images##############
bckgrnd = pygame.image.load("images/background 2.jfif") # background image
bckgrnd = pygame.transform.smoothscale(bckgrnd, (window_width,window_height)) #resizing background

xImage = pygame.image.load("images/x image.png") # loading x Image
oImage = pygame.image.load("images/o image.png")

#########others###################
places = {"1x1":" ","1x2":" ","1x3":" ","2x1":" ","2x2":" ","2x3":" ","3x1":" ","3x2":" ","3x3":" "}
turn = "player"


############# Fucntions ############
def arena():
    ####drawing lines####
    pygame.draw.line(canvas, (0,0,0),(650,100),(650,750),10)
    pygame.draw.line(canvas, (0,0,0),(900,100),(900,750),10)
    
    pygame.draw.line(canvas, (0,0,0),(450,300),(1100,300),10)
    pygame.draw.line(canvas, (0,0,0),(450,550),(1100,550),10)
    
    ####curving the edges of lines####
    pygame.draw.circle(canvas, (0,0,0), (1103,301), 5)
    pygame.draw.circle(canvas, (0,0,0), (450,301), 5)
    pygame.draw.circle(canvas, (0,0,0), (450,551), 5)
    pygame.draw.circle(canvas, (0,0,0), (1100,551), 5)
    pygame.draw.circle(canvas, (0,0,0), (901,100), 5)
    pygame.draw.circle(canvas, (0,0,0), (651,100), 5)
    pygame.draw.circle(canvas, (0,0,0), (651,750), 5)
    pygame.draw.circle(canvas, (0,0,0), (901,750), 5)

def checkX(): #drawing x
    if places["1x1"] == "x":
        canvas.blit(xImage, (450,100))
    if places["1x2"] == "x":
        canvas.blit(xImage, (690,100))
    if places["1x3"] == "x":
        canvas.blit(xImage, (920,100))
    if places["2x1"] == "x":
        canvas.blit(xImage, (450,340))
    if places["2x2"] == "x":
        canvas.blit(xImage,(690,340))
    if places["2x3"] == "x":
        canvas.blit(xImage, (920,340))
    if places["3x1"] == "x":
        canvas.blit(xImage, (450,570))
    if places["3x2"] == "x":
        canvas.blit(xImage, (690,570))
    if places["3x3"] == "x":
        canvas.blit(xImage,(920,570))

def checkO():
    if places["1x1"] == "o":
        canvas.blit(oImage, (450,100))
    if places["1x2"] == "o":
        canvas.blit(oImage, (690,100))
    if places["1x3"] == "o":
        canvas.blit(oImage, (920,100))
    if places["2x1"] == "o":
        canvas.blit(oImage, (450,340))
    if places["2x2"] == "o":
        canvas.blit(oImage,(690,340))
    if places["2x3"] == "o":
        canvas.blit(oImage, (920,340))
    if places["3x1"] == "o":
        canvas.blit(oImage, (450,570))
    if places["3x2"] == "o":
        canvas.blit(oImage, (690,570))
    if places["3x3"] == "o":
        canvas.blit(oImage,(920,570))
    
    
########classes###############   
class players: # player class
    def __init__(self,canvas,places,turn): # initialzing variables
        self.canvas = canvas
        self.places = places
        self.turn = turn
    def mouse(self,event): # mouse detection
        self.event = event
        #######mouse position#########
        self.mouseX = pygame.mouse.get_pos()[0]
        self.mouseY = pygame.mouse.get_pos()[1]
        
        if self.event.type == pygame.MOUSEBUTTONDOWN:
            ######1st line detection#######
            if self.mouseX < 650 and self.mouseX > 450:
                if self.mouseY < 300 and self.mouseY > 100:
                    self.places["1x1"] = "x"
                    self.turn = "computer"
                    
            if self.mouseX < 900 and self.mouseX > 650:
                if self.mouseY < 300 and self.mouseY > 100:
                    self.places["1x2"] = "x"
                    self.turn = "computer"
            
            if self.mouseX < 1100 and self.mouseX > 900:
                if self.mouseY < 300 and self.mouseY > 100:
                    self.places["1x3"] = "x"
                    self.turn = "computer"
            #######2nd line detection########                    
            if self.mouseX < 650 and self.mouseX > 450:
                if self.mouseY < 550 and self.mouseY > 300:
                    self.places["2x1"] = "x"
                    self.turn = "computer"
            if self.mouseX < 900 and self.mouseX > 650:
                if self.mouseY < 550 and self.mouseY > 300:
                    self.places["2x2"] = "x"
                    self.turn = "computer"
            if self.mouseX < 1100 and self.mouseX > 900:
                if self.mouseY < 550 and self.mouseY > 300:
                    self.places["2x3"] = "x"
                    self.turn = "computer"
            ###########3rd line detection###########
            if self.mouseX < 650 and self.mouseX > 450:
                if self.mouseY < 900 and self.mouseY > 550:
                    self.places["3x1"] = "x"
                    self.turn = "computer"
            if self.mouseX < 900 and self.mouseX > 650:
                if self.mouseY < 900 and self.mouseY > 550:
                    self.places["3x2"] = "x"
                    self.turn = "computer"
            if self.mouseX < 1100 and self.mouseX > 900:
                if self.mouseY < 900 and self.mouseY > 550:
                    self.places["3x3"] = "x"
                    self.turn = "computer"
        
class comp:
    def __init__(self,canvas,places):
        self.canvas = canvas
        self.places = places
    def rand(self): 
        self.ran = random.choice(list(self.places.keys()))
        if self.ran == "1x1":
            player.turn = "player"
            self.places["1x1"] = "o"
        if self.ran == "1x2":
            player.turn = "player"
            self.places["1x2"] = "o"
        if self.ran == "1x3":
            player.turn = "player"
            self.places["1x3"] = "o"
        if self.ran == "2x1":
            player.turn = "player"
            self.places["2x1"] = "o"
        if self.ran == "2x2":
            player.turn = "player"
            self.places["2x2"] = "o"
        if self.ran == "2x3":
            player.turn = "player"
            self.places["2x3"] = "o"
        if self.ran == "3x1":
            player.turn = "player"
            self.places["3x1"] = "o"
        if self.ran == "3x2":
            player.turn = "player"
            self.places["3x2"] = "o"
        if self.ran == "3x3":
            player.turn = "player"
            self.places["3x3"] = "o"
        
        
                
    def defend(self):   
        if self.places["1x1"] == "x" and self.places["1x2"] == "x":
            self.places["1x3"] = "o"
            player.turn = "player"
        if self.places["1x1"] == "x" and self.places["2x1"] == "x":
            self.places["3x1"] = "o"
            player.turn = "player"
        if self.places["1x2"] == "x" and self.places["1x3"] == "x":
            self.places["1x1"] = "o"
            player.turn = "player"
        if self.places["3x1"] == "x" and self.places["2x1"] == "x":
            self.places["1x1"] = "o"
            player.turn = "player"
        if self.places["3x1"] == "x" and self.places["1x1"] == "x":
            self.places["2x1"] = "o"
            player.turn = "player"
        if self.places["1x1"] == "x" and self.places["2x2"] == "x":
            self.places["3x3"] = "o"
            player.turn = "player"
        if self.places["1x2"] == "x" and self.places["2x2"] == "x":
            self.places["3x2"] = "o"
            player.turn = "player"
        
        else:
            self.rand()
            player.turn = "player"
        
        
    
    
player = players(canvas,places,turn)
computer = comp(canvas,places)

while True: #main loop
    for event in pygame.event.get(): # event handler
        if event.type == pygame.QUIT:
            pygame.quit()
            from sys import exit
            exit()
    canvas.blit(bckgrnd, (0,0)) # drawing background
    arena()
    if player.turn == "player":
        player.mouse(event)
    checkX() #draw X
    if player.turn == "computer":
        computer.defend()
    checkO() #draw O
    pygame.display.update()    

Please help, this thing has been troubling for a month. Thanks


Solution

  • There are two issues in your code:

    1. You are resending the mouse event every time you execute the loop, instead of when it actually occurs.

    To fix this I moved the mouse event inside the event loop:

    while True: #main loop
        for event in pygame.event.get(): # event handler
            if event.type == pygame.QUIT:
                pygame.quit()
                from sys import exit
                exit()
            if player.turn == "player":
                player.mouse(event)
        canvas.blit(bckgrnd, (0,0)) # drawing background
        arena()
    
        checkX() #draw X
        if player.turn == "computer":
            player.turn = computer.defend()
        checkO() #draw O
        pygame.display.update()
    
    1. You are referencing to a local variable player.turn inside of class comp, ionstead of referencing the variable of the player class.

    To fix this I return the turn variable of the computer object and assign it to the turn variable of the player object:

        def defend(self):
            if self.places["1x1"] == "x" and self.places["1x2"] == "x":
                self.places["1x3"] = "o"
                player.turn = "player"
            elif self.places["1x1"] == "x" and self.places["2x1"] == "x":
                self.places["3x1"] = "o"
                player.turn = "player"
            elif self.places["1x2"] == "x" and self.places["1x3"] == "x":
                self.places["1x1"] = "o"
                player.turn = "player"
            elif self.places["3x1"] == "x" and self.places["2x1"] == "x":
                self.places["1x1"] = "o"
                player.turn = "player"
            elif self.places["3x1"] == "x" and self.places["1x1"] == "x":
                self.places["2x1"] = "o"
                player.turn = "player"
            elif self.places["1x1"] == "x" and self.places["2x2"] == "x":
                self.places["3x3"] = "o"
                player.turn = "player"
            elif self.places["1x2"] == "x" and self.places["2x2"] == "x":
                self.places["3x2"] = "o"
                player.turn = "player"
            else:
                player.turn = "player"
                self.rand()
    
            return player.turn
    
    # inside the main loop:
    
    if player.turn == "computer":
            player.turn = computer.defend()