Simon memory game in pygame

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
6
down vote

favorite












I've been teaching myself python and I decided to make a Simon copy. Please let me know if there's anything notable that I should improve on. I understand my use of globals in some functions is considered poor, but I couldn't think of any other way to write them. Thank you for reading



import pygame
from random import randint
from time import sleep

pygame.init()
(width, height) = (450, 450)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Simon')
pygame.display.flip()
red = [255, 0, 0]
green = [0, 255, 0]
blue = [0, 0, 255]
yellow = [255, 255, 0]


class Button:
def __init__(self, color, pos):
self.color = color
self.pos = pos
self.shape = pygame.Rect
self.draw()

def draw(self):
self.shape = pygame.draw.rect(screen, self.color, self.pos)

def darken(self):
index = 0
for i in self.color:
if i == 255:
i -= 95
self.color[index] = i
index += 1
self.draw()
pygame.display.update()

def lighten(self):
index = 0
for i in self.color:
if i == 160:
i += 95
self.color[index] = i
index += 1
self.draw()
pygame.display.update()

def dark_then_light(self):
self.darken()
beep()
sleep(.5)
self.lighten()


red_square = Button(red, (25, 25, 200, 200))
green_square = Button(green, (225, 25, 200, 200))
blue_square = Button(blue, (25, 225, 200, 200))
yellow_square = Button(yellow, (225, 225, 200, 200))
pygame.display.update()

beep_sound = pygame.mixer.Sound('beep.wav')
intro_sound = pygame.mixer.Sound('intro.wav')


def intro():
intro_sound.play()


def beep():
beep_sound.play()


def click():
global player_list
pos = pygame.mouse.get_pos()
if (25 < pos[0] < 225) and (25 < pos[1] < 225):
press(0)
player_list.append(0)
elif (225 < pos[0] < 425) and (25 < pos[1] < 225):
press(1)
player_list.append(1)
elif (25 < pos[0] < 225) and (225 < pos[1] < 425):
press(2)
player_list.append(2)
elif (225 < pos[0] < 425) and (225 < pos[1] < 425):
press(3)
player_list.append(3)


def press(index):
if index == 0:
red_square.dark_then_light()
elif index == 1:
green_square.dark_then_light()
elif index == 2:
blue_square.dark_then_light()
elif index == 3:
yellow_square.dark_then_light()


font_name = pygame.font.match_font('arial')


def draw_text(surf, text, size, x, y):
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, (255, 255, 255))
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surf.blit(text_surface, text_rect)


def erase_text():
pygame.draw.rect(screen, (0, 0, 0), (0, 0, 450, 25))


correct_list =
player_list =


def ai_turn():
global AI_turn, player_turn, correct_list
index = randint(0, 3)
correct_list.append(index)
for i in correct_list:
press(i)
sleep(.15)
AI_turn = False
player_turn = True


def check():
global correct_list, player_list, DEFEAT
if len(correct_list) == len(player_list):
if correct_list == player_list:
return True
else:
DEFEAT = True
return False


END_SCREEN = True
running = True
AI_turn = True
player_turn = False
DEFEAT = False
score = 0

intro()
sleep(6)

while running:
if AI_turn:
erase_text()
draw_text(screen, 'SIMON'S TURN', 20, 225, 2, )
pygame.display.update()
sleep(.5)
ai_turn()
if player_turn:
erase_text()
draw_text(screen, 'PLAYER'S TURN', 20, 225, 2, )
pygame.display.update()
for event in pygame.event.get():
if not DEFEAT:
if event.type == pygame.QUIT:
running = False
END_SCREEN = False
if event.type == pygame.MOUSEBUTTONDOWN:
click()
if check():
AI_turn = True
player_turn = False
player_list =
score += 1
break
else:
break
if DEFEAT:
break

screen.fill((0, 0, 0))
draw_text(screen, 'YOU LOSE!!!', 50, 225, 200)
draw_text(screen, 'SCORE:', 50, 225, 255)
draw_text(screen, str(score), 50, 225, 305)
pygame.display.update()

while END_SCREEN:
for event in pygame.event.get():
if event.type == pygame.QUIT:
END_SCREEN = False






share|improve this question

























    up vote
    6
    down vote

    favorite












    I've been teaching myself python and I decided to make a Simon copy. Please let me know if there's anything notable that I should improve on. I understand my use of globals in some functions is considered poor, but I couldn't think of any other way to write them. Thank you for reading



    import pygame
    from random import randint
    from time import sleep

    pygame.init()
    (width, height) = (450, 450)
    screen = pygame.display.set_mode((width, height))
    pygame.display.set_caption('Simon')
    pygame.display.flip()
    red = [255, 0, 0]
    green = [0, 255, 0]
    blue = [0, 0, 255]
    yellow = [255, 255, 0]


    class Button:
    def __init__(self, color, pos):
    self.color = color
    self.pos = pos
    self.shape = pygame.Rect
    self.draw()

    def draw(self):
    self.shape = pygame.draw.rect(screen, self.color, self.pos)

    def darken(self):
    index = 0
    for i in self.color:
    if i == 255:
    i -= 95
    self.color[index] = i
    index += 1
    self.draw()
    pygame.display.update()

    def lighten(self):
    index = 0
    for i in self.color:
    if i == 160:
    i += 95
    self.color[index] = i
    index += 1
    self.draw()
    pygame.display.update()

    def dark_then_light(self):
    self.darken()
    beep()
    sleep(.5)
    self.lighten()


    red_square = Button(red, (25, 25, 200, 200))
    green_square = Button(green, (225, 25, 200, 200))
    blue_square = Button(blue, (25, 225, 200, 200))
    yellow_square = Button(yellow, (225, 225, 200, 200))
    pygame.display.update()

    beep_sound = pygame.mixer.Sound('beep.wav')
    intro_sound = pygame.mixer.Sound('intro.wav')


    def intro():
    intro_sound.play()


    def beep():
    beep_sound.play()


    def click():
    global player_list
    pos = pygame.mouse.get_pos()
    if (25 < pos[0] < 225) and (25 < pos[1] < 225):
    press(0)
    player_list.append(0)
    elif (225 < pos[0] < 425) and (25 < pos[1] < 225):
    press(1)
    player_list.append(1)
    elif (25 < pos[0] < 225) and (225 < pos[1] < 425):
    press(2)
    player_list.append(2)
    elif (225 < pos[0] < 425) and (225 < pos[1] < 425):
    press(3)
    player_list.append(3)


    def press(index):
    if index == 0:
    red_square.dark_then_light()
    elif index == 1:
    green_square.dark_then_light()
    elif index == 2:
    blue_square.dark_then_light()
    elif index == 3:
    yellow_square.dark_then_light()


    font_name = pygame.font.match_font('arial')


    def draw_text(surf, text, size, x, y):
    font = pygame.font.Font(font_name, size)
    text_surface = font.render(text, True, (255, 255, 255))
    text_rect = text_surface.get_rect()
    text_rect.midtop = (x, y)
    surf.blit(text_surface, text_rect)


    def erase_text():
    pygame.draw.rect(screen, (0, 0, 0), (0, 0, 450, 25))


    correct_list =
    player_list =


    def ai_turn():
    global AI_turn, player_turn, correct_list
    index = randint(0, 3)
    correct_list.append(index)
    for i in correct_list:
    press(i)
    sleep(.15)
    AI_turn = False
    player_turn = True


    def check():
    global correct_list, player_list, DEFEAT
    if len(correct_list) == len(player_list):
    if correct_list == player_list:
    return True
    else:
    DEFEAT = True
    return False


    END_SCREEN = True
    running = True
    AI_turn = True
    player_turn = False
    DEFEAT = False
    score = 0

    intro()
    sleep(6)

    while running:
    if AI_turn:
    erase_text()
    draw_text(screen, 'SIMON'S TURN', 20, 225, 2, )
    pygame.display.update()
    sleep(.5)
    ai_turn()
    if player_turn:
    erase_text()
    draw_text(screen, 'PLAYER'S TURN', 20, 225, 2, )
    pygame.display.update()
    for event in pygame.event.get():
    if not DEFEAT:
    if event.type == pygame.QUIT:
    running = False
    END_SCREEN = False
    if event.type == pygame.MOUSEBUTTONDOWN:
    click()
    if check():
    AI_turn = True
    player_turn = False
    player_list =
    score += 1
    break
    else:
    break
    if DEFEAT:
    break

    screen.fill((0, 0, 0))
    draw_text(screen, 'YOU LOSE!!!', 50, 225, 200)
    draw_text(screen, 'SCORE:', 50, 225, 255)
    draw_text(screen, str(score), 50, 225, 305)
    pygame.display.update()

    while END_SCREEN:
    for event in pygame.event.get():
    if event.type == pygame.QUIT:
    END_SCREEN = False






    share|improve this question





















      up vote
      6
      down vote

      favorite









      up vote
      6
      down vote

      favorite











      I've been teaching myself python and I decided to make a Simon copy. Please let me know if there's anything notable that I should improve on. I understand my use of globals in some functions is considered poor, but I couldn't think of any other way to write them. Thank you for reading



      import pygame
      from random import randint
      from time import sleep

      pygame.init()
      (width, height) = (450, 450)
      screen = pygame.display.set_mode((width, height))
      pygame.display.set_caption('Simon')
      pygame.display.flip()
      red = [255, 0, 0]
      green = [0, 255, 0]
      blue = [0, 0, 255]
      yellow = [255, 255, 0]


      class Button:
      def __init__(self, color, pos):
      self.color = color
      self.pos = pos
      self.shape = pygame.Rect
      self.draw()

      def draw(self):
      self.shape = pygame.draw.rect(screen, self.color, self.pos)

      def darken(self):
      index = 0
      for i in self.color:
      if i == 255:
      i -= 95
      self.color[index] = i
      index += 1
      self.draw()
      pygame.display.update()

      def lighten(self):
      index = 0
      for i in self.color:
      if i == 160:
      i += 95
      self.color[index] = i
      index += 1
      self.draw()
      pygame.display.update()

      def dark_then_light(self):
      self.darken()
      beep()
      sleep(.5)
      self.lighten()


      red_square = Button(red, (25, 25, 200, 200))
      green_square = Button(green, (225, 25, 200, 200))
      blue_square = Button(blue, (25, 225, 200, 200))
      yellow_square = Button(yellow, (225, 225, 200, 200))
      pygame.display.update()

      beep_sound = pygame.mixer.Sound('beep.wav')
      intro_sound = pygame.mixer.Sound('intro.wav')


      def intro():
      intro_sound.play()


      def beep():
      beep_sound.play()


      def click():
      global player_list
      pos = pygame.mouse.get_pos()
      if (25 < pos[0] < 225) and (25 < pos[1] < 225):
      press(0)
      player_list.append(0)
      elif (225 < pos[0] < 425) and (25 < pos[1] < 225):
      press(1)
      player_list.append(1)
      elif (25 < pos[0] < 225) and (225 < pos[1] < 425):
      press(2)
      player_list.append(2)
      elif (225 < pos[0] < 425) and (225 < pos[1] < 425):
      press(3)
      player_list.append(3)


      def press(index):
      if index == 0:
      red_square.dark_then_light()
      elif index == 1:
      green_square.dark_then_light()
      elif index == 2:
      blue_square.dark_then_light()
      elif index == 3:
      yellow_square.dark_then_light()


      font_name = pygame.font.match_font('arial')


      def draw_text(surf, text, size, x, y):
      font = pygame.font.Font(font_name, size)
      text_surface = font.render(text, True, (255, 255, 255))
      text_rect = text_surface.get_rect()
      text_rect.midtop = (x, y)
      surf.blit(text_surface, text_rect)


      def erase_text():
      pygame.draw.rect(screen, (0, 0, 0), (0, 0, 450, 25))


      correct_list =
      player_list =


      def ai_turn():
      global AI_turn, player_turn, correct_list
      index = randint(0, 3)
      correct_list.append(index)
      for i in correct_list:
      press(i)
      sleep(.15)
      AI_turn = False
      player_turn = True


      def check():
      global correct_list, player_list, DEFEAT
      if len(correct_list) == len(player_list):
      if correct_list == player_list:
      return True
      else:
      DEFEAT = True
      return False


      END_SCREEN = True
      running = True
      AI_turn = True
      player_turn = False
      DEFEAT = False
      score = 0

      intro()
      sleep(6)

      while running:
      if AI_turn:
      erase_text()
      draw_text(screen, 'SIMON'S TURN', 20, 225, 2, )
      pygame.display.update()
      sleep(.5)
      ai_turn()
      if player_turn:
      erase_text()
      draw_text(screen, 'PLAYER'S TURN', 20, 225, 2, )
      pygame.display.update()
      for event in pygame.event.get():
      if not DEFEAT:
      if event.type == pygame.QUIT:
      running = False
      END_SCREEN = False
      if event.type == pygame.MOUSEBUTTONDOWN:
      click()
      if check():
      AI_turn = True
      player_turn = False
      player_list =
      score += 1
      break
      else:
      break
      if DEFEAT:
      break

      screen.fill((0, 0, 0))
      draw_text(screen, 'YOU LOSE!!!', 50, 225, 200)
      draw_text(screen, 'SCORE:', 50, 225, 255)
      draw_text(screen, str(score), 50, 225, 305)
      pygame.display.update()

      while END_SCREEN:
      for event in pygame.event.get():
      if event.type == pygame.QUIT:
      END_SCREEN = False






      share|improve this question











      I've been teaching myself python and I decided to make a Simon copy. Please let me know if there's anything notable that I should improve on. I understand my use of globals in some functions is considered poor, but I couldn't think of any other way to write them. Thank you for reading



      import pygame
      from random import randint
      from time import sleep

      pygame.init()
      (width, height) = (450, 450)
      screen = pygame.display.set_mode((width, height))
      pygame.display.set_caption('Simon')
      pygame.display.flip()
      red = [255, 0, 0]
      green = [0, 255, 0]
      blue = [0, 0, 255]
      yellow = [255, 255, 0]


      class Button:
      def __init__(self, color, pos):
      self.color = color
      self.pos = pos
      self.shape = pygame.Rect
      self.draw()

      def draw(self):
      self.shape = pygame.draw.rect(screen, self.color, self.pos)

      def darken(self):
      index = 0
      for i in self.color:
      if i == 255:
      i -= 95
      self.color[index] = i
      index += 1
      self.draw()
      pygame.display.update()

      def lighten(self):
      index = 0
      for i in self.color:
      if i == 160:
      i += 95
      self.color[index] = i
      index += 1
      self.draw()
      pygame.display.update()

      def dark_then_light(self):
      self.darken()
      beep()
      sleep(.5)
      self.lighten()


      red_square = Button(red, (25, 25, 200, 200))
      green_square = Button(green, (225, 25, 200, 200))
      blue_square = Button(blue, (25, 225, 200, 200))
      yellow_square = Button(yellow, (225, 225, 200, 200))
      pygame.display.update()

      beep_sound = pygame.mixer.Sound('beep.wav')
      intro_sound = pygame.mixer.Sound('intro.wav')


      def intro():
      intro_sound.play()


      def beep():
      beep_sound.play()


      def click():
      global player_list
      pos = pygame.mouse.get_pos()
      if (25 < pos[0] < 225) and (25 < pos[1] < 225):
      press(0)
      player_list.append(0)
      elif (225 < pos[0] < 425) and (25 < pos[1] < 225):
      press(1)
      player_list.append(1)
      elif (25 < pos[0] < 225) and (225 < pos[1] < 425):
      press(2)
      player_list.append(2)
      elif (225 < pos[0] < 425) and (225 < pos[1] < 425):
      press(3)
      player_list.append(3)


      def press(index):
      if index == 0:
      red_square.dark_then_light()
      elif index == 1:
      green_square.dark_then_light()
      elif index == 2:
      blue_square.dark_then_light()
      elif index == 3:
      yellow_square.dark_then_light()


      font_name = pygame.font.match_font('arial')


      def draw_text(surf, text, size, x, y):
      font = pygame.font.Font(font_name, size)
      text_surface = font.render(text, True, (255, 255, 255))
      text_rect = text_surface.get_rect()
      text_rect.midtop = (x, y)
      surf.blit(text_surface, text_rect)


      def erase_text():
      pygame.draw.rect(screen, (0, 0, 0), (0, 0, 450, 25))


      correct_list =
      player_list =


      def ai_turn():
      global AI_turn, player_turn, correct_list
      index = randint(0, 3)
      correct_list.append(index)
      for i in correct_list:
      press(i)
      sleep(.15)
      AI_turn = False
      player_turn = True


      def check():
      global correct_list, player_list, DEFEAT
      if len(correct_list) == len(player_list):
      if correct_list == player_list:
      return True
      else:
      DEFEAT = True
      return False


      END_SCREEN = True
      running = True
      AI_turn = True
      player_turn = False
      DEFEAT = False
      score = 0

      intro()
      sleep(6)

      while running:
      if AI_turn:
      erase_text()
      draw_text(screen, 'SIMON'S TURN', 20, 225, 2, )
      pygame.display.update()
      sleep(.5)
      ai_turn()
      if player_turn:
      erase_text()
      draw_text(screen, 'PLAYER'S TURN', 20, 225, 2, )
      pygame.display.update()
      for event in pygame.event.get():
      if not DEFEAT:
      if event.type == pygame.QUIT:
      running = False
      END_SCREEN = False
      if event.type == pygame.MOUSEBUTTONDOWN:
      click()
      if check():
      AI_turn = True
      player_turn = False
      player_list =
      score += 1
      break
      else:
      break
      if DEFEAT:
      break

      screen.fill((0, 0, 0))
      draw_text(screen, 'YOU LOSE!!!', 50, 225, 200)
      draw_text(screen, 'SCORE:', 50, 225, 255)
      draw_text(screen, str(score), 50, 225, 305)
      pygame.display.update()

      while END_SCREEN:
      for event in pygame.event.get():
      if event.type == pygame.QUIT:
      END_SCREEN = False








      share|improve this question










      share|improve this question




      share|improve this question









      asked Jun 22 at 2:39









      Zackattackz

      333




      333




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          Good job so far.



          Major issues



          • The most important (game breaking) problem is that the game will become unresponsive if you don't make some sort of call to the event queue regularly, and when that happens (for example when the correct_list becomes too large and sleep gets called too often) you can't see which buttons the AI is clicking anymore.

          A quick fix would be to call pygame.event.pump() in the ai_turn function:



          def ai_turn():
          global AI_turn, player_turn, correct_list
          index = randint(0, 3)
          correct_list.append(index)
          for i in correct_list:
          pygame.event.pump()
          press(i)
          sleep(.15)
          AI_turn = False
          player_turn = True


          • I think it would be better to restructure the main while loop. In most games the event handling, game logic and the rendering are done separately, but here it's all intertwined.


          • It would be a good idea to reduce the amount of global variables. Pass the variables to the functions that need them and then return something and bind the returned value to a variable.


          Medium issues



          • Instead of changing the colors in the Button's darken and lighten methods, you could just pass the light and dark color and make them attributes of the class. Then pass the desired color to the draw method.


          • I'd also assign the rect to a self.rect attribute and remove the pos and shape attributes. You don't have to reassign the rect returned by pygame.draw.rect, since the rect shape won't change anyway.


          • pygame.Rects have handy collision detection methods (collidepoint would be helpful here).


          • The buttons can be put into a list. That makes it possible to iterate over the buttons with a for loop and you can shorten the click and press functions quite a bit.


          • Actually, I'd replace click and press with a function that checks which button was clicked and then check if it was the correct button. In order to make that work, you have to append the button objects (references) to the correct_list instead of the indices.


          Minor issues



          • PEP 8 (capitalized words are for constants).


          • Define a pygame.time.Clock instance and call clock.tick(frame_rate) every frame to limit the frame rate.


          • time.sleep should usually not be called in games, since it stops the execution of the rest of the program and makes the game unresponsive. However, for this particular game, I think it's okay and it probably doesn't need to be replaced.


          • One more tip: If you set os.environ['SDL_VIDEO_CENTERED'] = '1', the pygame window will be centered and I think that also moves it to the front (if other windows are open in the foreground).


          Gameplay



          • I think the game should stop when a wrong button is clicked, so that you don't have to keep clicking (unless the original worked in this way). I'm using the index variable in my example for this purpose and have removed the player_list.


          • It would be nice if the game could be restarted when it's over instead of having to execute the program again. The while loops and the corresponding variables could be put into different functions to make it easier to restart the game.


          Here's the complete example:



          import os
          from random import randint
          from time import sleep

          import pygame


          class Button:
          def __init__(self, color, dark_color, pos):
          self.color = color
          self.dark_color = dark_color
          self.rect = pygame.Rect(pos)
          self.draw(screen, self.color)

          def draw(self, screen, color):
          pygame.draw.rect(screen, color, self.rect)
          pygame.display.update()

          def dark_then_light(self, screen):
          self.draw(screen, self.dark_color)
          sleep(.5)
          self.draw(screen, self.color)


          def clicked_button(mouse_pos, buttons):
          """Return the clicked button or None if no button was clicked."""
          for button in buttons:
          if button.rect.collidepoint(mouse_pos):
          return button
          return None # Return None if no button was clicked.


          # Takes a font object now instead of creating a new one.
          def draw_text(surf, text, font, x, y):
          text_surface = font.render(text, True, (255, 255, 255))
          text_rect = text_surface.get_rect()
          text_rect.midtop = (x, y)
          surf.blit(text_surface, text_rect)


          def erase_text():
          pygame.draw.rect(screen, (0, 0, 0), (0, 0, 450, 25))


          os.environ['SDL_VIDEO_CENTERED'] = '1'
          pygame.init()
          screen = pygame.display.set_mode((450, 450))
          clock = pygame.time.Clock() # A clock to limit the frame rate.
          pygame.display.set_caption('Simon')
          # Define the font objects once (for efficiency reasons).
          FONT = pygame.font.Font(pygame.font.match_font('arial'), 50)
          FONT_SMALL = pygame.font.Font(pygame.font.match_font('arial'), 20)

          end_screen = True
          running = True
          ai_turn = True
          score = 0
          correct_list =
          index = 0
          buttons = [
          Button(pygame.Color('red'), pygame.Color(160, 0, 0), (25, 25, 200, 200)),
          Button(pygame.Color('green'), pygame.Color(0, 160, 0), (225, 25, 200, 200)),
          Button(pygame.Color('blue'), pygame.Color(0, 0, 160), (25, 225, 200, 200)),
          Button(pygame.Color('yellow'), pygame.Color(160, 160, 0), (225, 225, 200, 200)),
          ]

          while running:
          for event in pygame.event.get():
          if event.type == pygame.QUIT:
          running = False
          end_screen = False
          elif event.type == pygame.MOUSEBUTTONDOWN and not ai_turn:
          correct_button = correct_list[index]
          button = clicked_button(event.pos, buttons)
          if button is None: # No button pressed.
          break
          elif button == correct_button: # Correct button pressed.
          button.dark_then_light(screen)
          index += 1
          if index == len(correct_list): # All buttons clicked.
          ai_turn = True
          score += 1
          index = 0
          else: # Wrong button pressed.
          running = False

          if ai_turn:
          erase_text()
          draw_text(screen, 'SIMON'S TURN', FONT_SMALL, 225, 2)
          pygame.display.update()
          ai_turn = False
          sleep(.5)
          # Append references to the button objects instead of indices.
          correct_list.append(buttons[randint(0, 3)])
          for button in correct_list:
          pygame.event.pump() # Prevent the game from freezing.
          button.dark_then_light(screen)
          sleep(.15)

          erase_text()
          draw_text(screen, 'PLAYER'S TURN', FONT_SMALL, 225, 2)
          pygame.display.update()

          clock.tick(30) # Limit the frame rate to 30 FPS.


          screen.fill((0, 0, 0))
          draw_text(screen, 'GAME OVER!!!', FONT, 225, 200)
          draw_text(screen, 'SCORE:', FONT, 225, 255)
          draw_text(screen, str(score), FONT, 225, 305)
          pygame.display.update()

          while end_screen:
          for event in pygame.event.get():
          if event.type == pygame.QUIT:
          end_screen = False

          clock.tick(30)


          In this example it's possible to click at the same time as the AI, but that should be impossible to prevent cheating. That needs to be fixed.



          And again, you already did a pretty good job and of course you don't have to implement all of these suggestions.






          share|improve this answer





















            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f197022%2fsimon-memory-game-in-pygame%23new-answer', 'question_page');

            );

            Post as a guest






























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            1
            down vote



            accepted










            Good job so far.



            Major issues



            • The most important (game breaking) problem is that the game will become unresponsive if you don't make some sort of call to the event queue regularly, and when that happens (for example when the correct_list becomes too large and sleep gets called too often) you can't see which buttons the AI is clicking anymore.

            A quick fix would be to call pygame.event.pump() in the ai_turn function:



            def ai_turn():
            global AI_turn, player_turn, correct_list
            index = randint(0, 3)
            correct_list.append(index)
            for i in correct_list:
            pygame.event.pump()
            press(i)
            sleep(.15)
            AI_turn = False
            player_turn = True


            • I think it would be better to restructure the main while loop. In most games the event handling, game logic and the rendering are done separately, but here it's all intertwined.


            • It would be a good idea to reduce the amount of global variables. Pass the variables to the functions that need them and then return something and bind the returned value to a variable.


            Medium issues



            • Instead of changing the colors in the Button's darken and lighten methods, you could just pass the light and dark color and make them attributes of the class. Then pass the desired color to the draw method.


            • I'd also assign the rect to a self.rect attribute and remove the pos and shape attributes. You don't have to reassign the rect returned by pygame.draw.rect, since the rect shape won't change anyway.


            • pygame.Rects have handy collision detection methods (collidepoint would be helpful here).


            • The buttons can be put into a list. That makes it possible to iterate over the buttons with a for loop and you can shorten the click and press functions quite a bit.


            • Actually, I'd replace click and press with a function that checks which button was clicked and then check if it was the correct button. In order to make that work, you have to append the button objects (references) to the correct_list instead of the indices.


            Minor issues



            • PEP 8 (capitalized words are for constants).


            • Define a pygame.time.Clock instance and call clock.tick(frame_rate) every frame to limit the frame rate.


            • time.sleep should usually not be called in games, since it stops the execution of the rest of the program and makes the game unresponsive. However, for this particular game, I think it's okay and it probably doesn't need to be replaced.


            • One more tip: If you set os.environ['SDL_VIDEO_CENTERED'] = '1', the pygame window will be centered and I think that also moves it to the front (if other windows are open in the foreground).


            Gameplay



            • I think the game should stop when a wrong button is clicked, so that you don't have to keep clicking (unless the original worked in this way). I'm using the index variable in my example for this purpose and have removed the player_list.


            • It would be nice if the game could be restarted when it's over instead of having to execute the program again. The while loops and the corresponding variables could be put into different functions to make it easier to restart the game.


            Here's the complete example:



            import os
            from random import randint
            from time import sleep

            import pygame


            class Button:
            def __init__(self, color, dark_color, pos):
            self.color = color
            self.dark_color = dark_color
            self.rect = pygame.Rect(pos)
            self.draw(screen, self.color)

            def draw(self, screen, color):
            pygame.draw.rect(screen, color, self.rect)
            pygame.display.update()

            def dark_then_light(self, screen):
            self.draw(screen, self.dark_color)
            sleep(.5)
            self.draw(screen, self.color)


            def clicked_button(mouse_pos, buttons):
            """Return the clicked button or None if no button was clicked."""
            for button in buttons:
            if button.rect.collidepoint(mouse_pos):
            return button
            return None # Return None if no button was clicked.


            # Takes a font object now instead of creating a new one.
            def draw_text(surf, text, font, x, y):
            text_surface = font.render(text, True, (255, 255, 255))
            text_rect = text_surface.get_rect()
            text_rect.midtop = (x, y)
            surf.blit(text_surface, text_rect)


            def erase_text():
            pygame.draw.rect(screen, (0, 0, 0), (0, 0, 450, 25))


            os.environ['SDL_VIDEO_CENTERED'] = '1'
            pygame.init()
            screen = pygame.display.set_mode((450, 450))
            clock = pygame.time.Clock() # A clock to limit the frame rate.
            pygame.display.set_caption('Simon')
            # Define the font objects once (for efficiency reasons).
            FONT = pygame.font.Font(pygame.font.match_font('arial'), 50)
            FONT_SMALL = pygame.font.Font(pygame.font.match_font('arial'), 20)

            end_screen = True
            running = True
            ai_turn = True
            score = 0
            correct_list =
            index = 0
            buttons = [
            Button(pygame.Color('red'), pygame.Color(160, 0, 0), (25, 25, 200, 200)),
            Button(pygame.Color('green'), pygame.Color(0, 160, 0), (225, 25, 200, 200)),
            Button(pygame.Color('blue'), pygame.Color(0, 0, 160), (25, 225, 200, 200)),
            Button(pygame.Color('yellow'), pygame.Color(160, 160, 0), (225, 225, 200, 200)),
            ]

            while running:
            for event in pygame.event.get():
            if event.type == pygame.QUIT:
            running = False
            end_screen = False
            elif event.type == pygame.MOUSEBUTTONDOWN and not ai_turn:
            correct_button = correct_list[index]
            button = clicked_button(event.pos, buttons)
            if button is None: # No button pressed.
            break
            elif button == correct_button: # Correct button pressed.
            button.dark_then_light(screen)
            index += 1
            if index == len(correct_list): # All buttons clicked.
            ai_turn = True
            score += 1
            index = 0
            else: # Wrong button pressed.
            running = False

            if ai_turn:
            erase_text()
            draw_text(screen, 'SIMON'S TURN', FONT_SMALL, 225, 2)
            pygame.display.update()
            ai_turn = False
            sleep(.5)
            # Append references to the button objects instead of indices.
            correct_list.append(buttons[randint(0, 3)])
            for button in correct_list:
            pygame.event.pump() # Prevent the game from freezing.
            button.dark_then_light(screen)
            sleep(.15)

            erase_text()
            draw_text(screen, 'PLAYER'S TURN', FONT_SMALL, 225, 2)
            pygame.display.update()

            clock.tick(30) # Limit the frame rate to 30 FPS.


            screen.fill((0, 0, 0))
            draw_text(screen, 'GAME OVER!!!', FONT, 225, 200)
            draw_text(screen, 'SCORE:', FONT, 225, 255)
            draw_text(screen, str(score), FONT, 225, 305)
            pygame.display.update()

            while end_screen:
            for event in pygame.event.get():
            if event.type == pygame.QUIT:
            end_screen = False

            clock.tick(30)


            In this example it's possible to click at the same time as the AI, but that should be impossible to prevent cheating. That needs to be fixed.



            And again, you already did a pretty good job and of course you don't have to implement all of these suggestions.






            share|improve this answer

























              up vote
              1
              down vote



              accepted










              Good job so far.



              Major issues



              • The most important (game breaking) problem is that the game will become unresponsive if you don't make some sort of call to the event queue regularly, and when that happens (for example when the correct_list becomes too large and sleep gets called too often) you can't see which buttons the AI is clicking anymore.

              A quick fix would be to call pygame.event.pump() in the ai_turn function:



              def ai_turn():
              global AI_turn, player_turn, correct_list
              index = randint(0, 3)
              correct_list.append(index)
              for i in correct_list:
              pygame.event.pump()
              press(i)
              sleep(.15)
              AI_turn = False
              player_turn = True


              • I think it would be better to restructure the main while loop. In most games the event handling, game logic and the rendering are done separately, but here it's all intertwined.


              • It would be a good idea to reduce the amount of global variables. Pass the variables to the functions that need them and then return something and bind the returned value to a variable.


              Medium issues



              • Instead of changing the colors in the Button's darken and lighten methods, you could just pass the light and dark color and make them attributes of the class. Then pass the desired color to the draw method.


              • I'd also assign the rect to a self.rect attribute and remove the pos and shape attributes. You don't have to reassign the rect returned by pygame.draw.rect, since the rect shape won't change anyway.


              • pygame.Rects have handy collision detection methods (collidepoint would be helpful here).


              • The buttons can be put into a list. That makes it possible to iterate over the buttons with a for loop and you can shorten the click and press functions quite a bit.


              • Actually, I'd replace click and press with a function that checks which button was clicked and then check if it was the correct button. In order to make that work, you have to append the button objects (references) to the correct_list instead of the indices.


              Minor issues



              • PEP 8 (capitalized words are for constants).


              • Define a pygame.time.Clock instance and call clock.tick(frame_rate) every frame to limit the frame rate.


              • time.sleep should usually not be called in games, since it stops the execution of the rest of the program and makes the game unresponsive. However, for this particular game, I think it's okay and it probably doesn't need to be replaced.


              • One more tip: If you set os.environ['SDL_VIDEO_CENTERED'] = '1', the pygame window will be centered and I think that also moves it to the front (if other windows are open in the foreground).


              Gameplay



              • I think the game should stop when a wrong button is clicked, so that you don't have to keep clicking (unless the original worked in this way). I'm using the index variable in my example for this purpose and have removed the player_list.


              • It would be nice if the game could be restarted when it's over instead of having to execute the program again. The while loops and the corresponding variables could be put into different functions to make it easier to restart the game.


              Here's the complete example:



              import os
              from random import randint
              from time import sleep

              import pygame


              class Button:
              def __init__(self, color, dark_color, pos):
              self.color = color
              self.dark_color = dark_color
              self.rect = pygame.Rect(pos)
              self.draw(screen, self.color)

              def draw(self, screen, color):
              pygame.draw.rect(screen, color, self.rect)
              pygame.display.update()

              def dark_then_light(self, screen):
              self.draw(screen, self.dark_color)
              sleep(.5)
              self.draw(screen, self.color)


              def clicked_button(mouse_pos, buttons):
              """Return the clicked button or None if no button was clicked."""
              for button in buttons:
              if button.rect.collidepoint(mouse_pos):
              return button
              return None # Return None if no button was clicked.


              # Takes a font object now instead of creating a new one.
              def draw_text(surf, text, font, x, y):
              text_surface = font.render(text, True, (255, 255, 255))
              text_rect = text_surface.get_rect()
              text_rect.midtop = (x, y)
              surf.blit(text_surface, text_rect)


              def erase_text():
              pygame.draw.rect(screen, (0, 0, 0), (0, 0, 450, 25))


              os.environ['SDL_VIDEO_CENTERED'] = '1'
              pygame.init()
              screen = pygame.display.set_mode((450, 450))
              clock = pygame.time.Clock() # A clock to limit the frame rate.
              pygame.display.set_caption('Simon')
              # Define the font objects once (for efficiency reasons).
              FONT = pygame.font.Font(pygame.font.match_font('arial'), 50)
              FONT_SMALL = pygame.font.Font(pygame.font.match_font('arial'), 20)

              end_screen = True
              running = True
              ai_turn = True
              score = 0
              correct_list =
              index = 0
              buttons = [
              Button(pygame.Color('red'), pygame.Color(160, 0, 0), (25, 25, 200, 200)),
              Button(pygame.Color('green'), pygame.Color(0, 160, 0), (225, 25, 200, 200)),
              Button(pygame.Color('blue'), pygame.Color(0, 0, 160), (25, 225, 200, 200)),
              Button(pygame.Color('yellow'), pygame.Color(160, 160, 0), (225, 225, 200, 200)),
              ]

              while running:
              for event in pygame.event.get():
              if event.type == pygame.QUIT:
              running = False
              end_screen = False
              elif event.type == pygame.MOUSEBUTTONDOWN and not ai_turn:
              correct_button = correct_list[index]
              button = clicked_button(event.pos, buttons)
              if button is None: # No button pressed.
              break
              elif button == correct_button: # Correct button pressed.
              button.dark_then_light(screen)
              index += 1
              if index == len(correct_list): # All buttons clicked.
              ai_turn = True
              score += 1
              index = 0
              else: # Wrong button pressed.
              running = False

              if ai_turn:
              erase_text()
              draw_text(screen, 'SIMON'S TURN', FONT_SMALL, 225, 2)
              pygame.display.update()
              ai_turn = False
              sleep(.5)
              # Append references to the button objects instead of indices.
              correct_list.append(buttons[randint(0, 3)])
              for button in correct_list:
              pygame.event.pump() # Prevent the game from freezing.
              button.dark_then_light(screen)
              sleep(.15)

              erase_text()
              draw_text(screen, 'PLAYER'S TURN', FONT_SMALL, 225, 2)
              pygame.display.update()

              clock.tick(30) # Limit the frame rate to 30 FPS.


              screen.fill((0, 0, 0))
              draw_text(screen, 'GAME OVER!!!', FONT, 225, 200)
              draw_text(screen, 'SCORE:', FONT, 225, 255)
              draw_text(screen, str(score), FONT, 225, 305)
              pygame.display.update()

              while end_screen:
              for event in pygame.event.get():
              if event.type == pygame.QUIT:
              end_screen = False

              clock.tick(30)


              In this example it's possible to click at the same time as the AI, but that should be impossible to prevent cheating. That needs to be fixed.



              And again, you already did a pretty good job and of course you don't have to implement all of these suggestions.






              share|improve this answer























                up vote
                1
                down vote



                accepted







                up vote
                1
                down vote



                accepted






                Good job so far.



                Major issues



                • The most important (game breaking) problem is that the game will become unresponsive if you don't make some sort of call to the event queue regularly, and when that happens (for example when the correct_list becomes too large and sleep gets called too often) you can't see which buttons the AI is clicking anymore.

                A quick fix would be to call pygame.event.pump() in the ai_turn function:



                def ai_turn():
                global AI_turn, player_turn, correct_list
                index = randint(0, 3)
                correct_list.append(index)
                for i in correct_list:
                pygame.event.pump()
                press(i)
                sleep(.15)
                AI_turn = False
                player_turn = True


                • I think it would be better to restructure the main while loop. In most games the event handling, game logic and the rendering are done separately, but here it's all intertwined.


                • It would be a good idea to reduce the amount of global variables. Pass the variables to the functions that need them and then return something and bind the returned value to a variable.


                Medium issues



                • Instead of changing the colors in the Button's darken and lighten methods, you could just pass the light and dark color and make them attributes of the class. Then pass the desired color to the draw method.


                • I'd also assign the rect to a self.rect attribute and remove the pos and shape attributes. You don't have to reassign the rect returned by pygame.draw.rect, since the rect shape won't change anyway.


                • pygame.Rects have handy collision detection methods (collidepoint would be helpful here).


                • The buttons can be put into a list. That makes it possible to iterate over the buttons with a for loop and you can shorten the click and press functions quite a bit.


                • Actually, I'd replace click and press with a function that checks which button was clicked and then check if it was the correct button. In order to make that work, you have to append the button objects (references) to the correct_list instead of the indices.


                Minor issues



                • PEP 8 (capitalized words are for constants).


                • Define a pygame.time.Clock instance and call clock.tick(frame_rate) every frame to limit the frame rate.


                • time.sleep should usually not be called in games, since it stops the execution of the rest of the program and makes the game unresponsive. However, for this particular game, I think it's okay and it probably doesn't need to be replaced.


                • One more tip: If you set os.environ['SDL_VIDEO_CENTERED'] = '1', the pygame window will be centered and I think that also moves it to the front (if other windows are open in the foreground).


                Gameplay



                • I think the game should stop when a wrong button is clicked, so that you don't have to keep clicking (unless the original worked in this way). I'm using the index variable in my example for this purpose and have removed the player_list.


                • It would be nice if the game could be restarted when it's over instead of having to execute the program again. The while loops and the corresponding variables could be put into different functions to make it easier to restart the game.


                Here's the complete example:



                import os
                from random import randint
                from time import sleep

                import pygame


                class Button:
                def __init__(self, color, dark_color, pos):
                self.color = color
                self.dark_color = dark_color
                self.rect = pygame.Rect(pos)
                self.draw(screen, self.color)

                def draw(self, screen, color):
                pygame.draw.rect(screen, color, self.rect)
                pygame.display.update()

                def dark_then_light(self, screen):
                self.draw(screen, self.dark_color)
                sleep(.5)
                self.draw(screen, self.color)


                def clicked_button(mouse_pos, buttons):
                """Return the clicked button or None if no button was clicked."""
                for button in buttons:
                if button.rect.collidepoint(mouse_pos):
                return button
                return None # Return None if no button was clicked.


                # Takes a font object now instead of creating a new one.
                def draw_text(surf, text, font, x, y):
                text_surface = font.render(text, True, (255, 255, 255))
                text_rect = text_surface.get_rect()
                text_rect.midtop = (x, y)
                surf.blit(text_surface, text_rect)


                def erase_text():
                pygame.draw.rect(screen, (0, 0, 0), (0, 0, 450, 25))


                os.environ['SDL_VIDEO_CENTERED'] = '1'
                pygame.init()
                screen = pygame.display.set_mode((450, 450))
                clock = pygame.time.Clock() # A clock to limit the frame rate.
                pygame.display.set_caption('Simon')
                # Define the font objects once (for efficiency reasons).
                FONT = pygame.font.Font(pygame.font.match_font('arial'), 50)
                FONT_SMALL = pygame.font.Font(pygame.font.match_font('arial'), 20)

                end_screen = True
                running = True
                ai_turn = True
                score = 0
                correct_list =
                index = 0
                buttons = [
                Button(pygame.Color('red'), pygame.Color(160, 0, 0), (25, 25, 200, 200)),
                Button(pygame.Color('green'), pygame.Color(0, 160, 0), (225, 25, 200, 200)),
                Button(pygame.Color('blue'), pygame.Color(0, 0, 160), (25, 225, 200, 200)),
                Button(pygame.Color('yellow'), pygame.Color(160, 160, 0), (225, 225, 200, 200)),
                ]

                while running:
                for event in pygame.event.get():
                if event.type == pygame.QUIT:
                running = False
                end_screen = False
                elif event.type == pygame.MOUSEBUTTONDOWN and not ai_turn:
                correct_button = correct_list[index]
                button = clicked_button(event.pos, buttons)
                if button is None: # No button pressed.
                break
                elif button == correct_button: # Correct button pressed.
                button.dark_then_light(screen)
                index += 1
                if index == len(correct_list): # All buttons clicked.
                ai_turn = True
                score += 1
                index = 0
                else: # Wrong button pressed.
                running = False

                if ai_turn:
                erase_text()
                draw_text(screen, 'SIMON'S TURN', FONT_SMALL, 225, 2)
                pygame.display.update()
                ai_turn = False
                sleep(.5)
                # Append references to the button objects instead of indices.
                correct_list.append(buttons[randint(0, 3)])
                for button in correct_list:
                pygame.event.pump() # Prevent the game from freezing.
                button.dark_then_light(screen)
                sleep(.15)

                erase_text()
                draw_text(screen, 'PLAYER'S TURN', FONT_SMALL, 225, 2)
                pygame.display.update()

                clock.tick(30) # Limit the frame rate to 30 FPS.


                screen.fill((0, 0, 0))
                draw_text(screen, 'GAME OVER!!!', FONT, 225, 200)
                draw_text(screen, 'SCORE:', FONT, 225, 255)
                draw_text(screen, str(score), FONT, 225, 305)
                pygame.display.update()

                while end_screen:
                for event in pygame.event.get():
                if event.type == pygame.QUIT:
                end_screen = False

                clock.tick(30)


                In this example it's possible to click at the same time as the AI, but that should be impossible to prevent cheating. That needs to be fixed.



                And again, you already did a pretty good job and of course you don't have to implement all of these suggestions.






                share|improve this answer













                Good job so far.



                Major issues



                • The most important (game breaking) problem is that the game will become unresponsive if you don't make some sort of call to the event queue regularly, and when that happens (for example when the correct_list becomes too large and sleep gets called too often) you can't see which buttons the AI is clicking anymore.

                A quick fix would be to call pygame.event.pump() in the ai_turn function:



                def ai_turn():
                global AI_turn, player_turn, correct_list
                index = randint(0, 3)
                correct_list.append(index)
                for i in correct_list:
                pygame.event.pump()
                press(i)
                sleep(.15)
                AI_turn = False
                player_turn = True


                • I think it would be better to restructure the main while loop. In most games the event handling, game logic and the rendering are done separately, but here it's all intertwined.


                • It would be a good idea to reduce the amount of global variables. Pass the variables to the functions that need them and then return something and bind the returned value to a variable.


                Medium issues



                • Instead of changing the colors in the Button's darken and lighten methods, you could just pass the light and dark color and make them attributes of the class. Then pass the desired color to the draw method.


                • I'd also assign the rect to a self.rect attribute and remove the pos and shape attributes. You don't have to reassign the rect returned by pygame.draw.rect, since the rect shape won't change anyway.


                • pygame.Rects have handy collision detection methods (collidepoint would be helpful here).


                • The buttons can be put into a list. That makes it possible to iterate over the buttons with a for loop and you can shorten the click and press functions quite a bit.


                • Actually, I'd replace click and press with a function that checks which button was clicked and then check if it was the correct button. In order to make that work, you have to append the button objects (references) to the correct_list instead of the indices.


                Minor issues



                • PEP 8 (capitalized words are for constants).


                • Define a pygame.time.Clock instance and call clock.tick(frame_rate) every frame to limit the frame rate.


                • time.sleep should usually not be called in games, since it stops the execution of the rest of the program and makes the game unresponsive. However, for this particular game, I think it's okay and it probably doesn't need to be replaced.


                • One more tip: If you set os.environ['SDL_VIDEO_CENTERED'] = '1', the pygame window will be centered and I think that also moves it to the front (if other windows are open in the foreground).


                Gameplay



                • I think the game should stop when a wrong button is clicked, so that you don't have to keep clicking (unless the original worked in this way). I'm using the index variable in my example for this purpose and have removed the player_list.


                • It would be nice if the game could be restarted when it's over instead of having to execute the program again. The while loops and the corresponding variables could be put into different functions to make it easier to restart the game.


                Here's the complete example:



                import os
                from random import randint
                from time import sleep

                import pygame


                class Button:
                def __init__(self, color, dark_color, pos):
                self.color = color
                self.dark_color = dark_color
                self.rect = pygame.Rect(pos)
                self.draw(screen, self.color)

                def draw(self, screen, color):
                pygame.draw.rect(screen, color, self.rect)
                pygame.display.update()

                def dark_then_light(self, screen):
                self.draw(screen, self.dark_color)
                sleep(.5)
                self.draw(screen, self.color)


                def clicked_button(mouse_pos, buttons):
                """Return the clicked button or None if no button was clicked."""
                for button in buttons:
                if button.rect.collidepoint(mouse_pos):
                return button
                return None # Return None if no button was clicked.


                # Takes a font object now instead of creating a new one.
                def draw_text(surf, text, font, x, y):
                text_surface = font.render(text, True, (255, 255, 255))
                text_rect = text_surface.get_rect()
                text_rect.midtop = (x, y)
                surf.blit(text_surface, text_rect)


                def erase_text():
                pygame.draw.rect(screen, (0, 0, 0), (0, 0, 450, 25))


                os.environ['SDL_VIDEO_CENTERED'] = '1'
                pygame.init()
                screen = pygame.display.set_mode((450, 450))
                clock = pygame.time.Clock() # A clock to limit the frame rate.
                pygame.display.set_caption('Simon')
                # Define the font objects once (for efficiency reasons).
                FONT = pygame.font.Font(pygame.font.match_font('arial'), 50)
                FONT_SMALL = pygame.font.Font(pygame.font.match_font('arial'), 20)

                end_screen = True
                running = True
                ai_turn = True
                score = 0
                correct_list =
                index = 0
                buttons = [
                Button(pygame.Color('red'), pygame.Color(160, 0, 0), (25, 25, 200, 200)),
                Button(pygame.Color('green'), pygame.Color(0, 160, 0), (225, 25, 200, 200)),
                Button(pygame.Color('blue'), pygame.Color(0, 0, 160), (25, 225, 200, 200)),
                Button(pygame.Color('yellow'), pygame.Color(160, 160, 0), (225, 225, 200, 200)),
                ]

                while running:
                for event in pygame.event.get():
                if event.type == pygame.QUIT:
                running = False
                end_screen = False
                elif event.type == pygame.MOUSEBUTTONDOWN and not ai_turn:
                correct_button = correct_list[index]
                button = clicked_button(event.pos, buttons)
                if button is None: # No button pressed.
                break
                elif button == correct_button: # Correct button pressed.
                button.dark_then_light(screen)
                index += 1
                if index == len(correct_list): # All buttons clicked.
                ai_turn = True
                score += 1
                index = 0
                else: # Wrong button pressed.
                running = False

                if ai_turn:
                erase_text()
                draw_text(screen, 'SIMON'S TURN', FONT_SMALL, 225, 2)
                pygame.display.update()
                ai_turn = False
                sleep(.5)
                # Append references to the button objects instead of indices.
                correct_list.append(buttons[randint(0, 3)])
                for button in correct_list:
                pygame.event.pump() # Prevent the game from freezing.
                button.dark_then_light(screen)
                sleep(.15)

                erase_text()
                draw_text(screen, 'PLAYER'S TURN', FONT_SMALL, 225, 2)
                pygame.display.update()

                clock.tick(30) # Limit the frame rate to 30 FPS.


                screen.fill((0, 0, 0))
                draw_text(screen, 'GAME OVER!!!', FONT, 225, 200)
                draw_text(screen, 'SCORE:', FONT, 225, 255)
                draw_text(screen, str(score), FONT, 225, 305)
                pygame.display.update()

                while end_screen:
                for event in pygame.event.get():
                if event.type == pygame.QUIT:
                end_screen = False

                clock.tick(30)


                In this example it's possible to click at the same time as the AI, but that should be impossible to prevent cheating. That needs to be fixed.



                And again, you already did a pretty good job and of course you don't have to implement all of these suggestions.







                share|improve this answer













                share|improve this answer



                share|improve this answer











                answered Jun 24 at 11:20









                skrx

                42138




                42138






















                     

                    draft saved


                    draft discarded


























                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f197022%2fsimon-memory-game-in-pygame%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Popular posts from this blog

                    Greedy Best First Search implementation in Rust

                    Function to Return a JSON Like Objects Using VBA Collections and Arrays

                    C++11 CLH Lock Implementation