text: ##Remember Me
  ## Jingyan Deng  Xichen Mao
  ## CIS 1051 Final Project 2021
  ## Works cited
  ## https://eng.libretexts.org/Bookshelves/Computer_Science/Book%3A_Making_Games_with_Python_and_Pygame_(Sweigart)/04%3A_Memory_Puzzle/4.03%3A_Source_Code_of_Memory_Puzzle 
  
  
  
  import random, pygame, sys
  from pygame.locals import *
  
  FPS = 30  
  WINDOWWIDTH = 720
  WINDOWHEIGHT = 720  
  REVEALSPEED = 8  
  BOXSIZE = 50  
  GAPSIZE = 10  
  BOARDWIDTH = 2  
  BOARDHEIGHT = 2 
  assert (BOARDWIDTH * BOARDHEIGHT) % 2 == 0, 'Board needs to have an even number of boxes for pairs of matches.'
  XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * (BOXSIZE + GAPSIZE))) / 2)
  YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * (BOXSIZE + GAPSIZE))) / 2)
  
  
  
  
  HOTPINK = (255, 105, 180)
  SKYBLUE = ( 135,  206, 235)
  FORESTGREEN = (34, 139, 34)
  FIREBRICK = (178,   34,   34)
  OLIVE = (128, 128,   0)
  MEDIUMPURPLE = (147,   112, 219)
  YELLOW  = (255, 255,   0)
  ORANGE  = (255, 128,   0)
  TAN   = (210,   180, 140)
  SNOW = (255, 250, 250)
  THISTLE = (216,191,216)
  PALEGREEN = (152,251,152)
  
  BGCOLOR = THISTLE
  LIGHTBGCOLOR = PALEGREEN
  BOXCOLOR = SNOW
  HIGHLIGHTCOLOR = MEDIUMPURPLE
  
  DONUT = 'donut'
  SQUARE = 'square'
  DIAMOND = 'diamond'
  LINES = 'lines'
  OVAL = 'oval'
  
  game_over = r'/Users/jingyandeng/Desktop/123.jpeg'
  mao = pygame.image.load(game_over)
  
  
  
  ALLCOLORS = (HOTPINK, SKYBLUE, FIREBRICK, YELLOW, ORANGE, TAN, FORESTGREEN, OLIVE)
  ALLSHAPES = (DONUT, SQUARE, DIAMOND, LINES, OVAL)
  assert len(ALLCOLORS) * len(ALLSHAPES) * 2 >= BOARDWIDTH * BOARDHEIGHT, "Board is too big for the number of shapes/colors defined."
  
  
  def main():
      global FPSCLOCK, DISPLAYSURF
      pygame.init()
      myfont = pygame.font.Font(None, 60)
      FPSCLOCK = pygame.time.Clock()
      DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT),0,32)
  
      mousex = 0  
      mousey = 0  
      pygame.display.set_caption('Remember Me')
  
      mainBoard = getRandomizedBoard()
      revealedBoxes = generateRevealedBoxesData(False)
  
      firstSelection = None  
  
      DISPLAYSURF.fill(BGCOLOR)
      startGameAnimation(mainBoard)
  
      while True:  
          mouseClicked = False
  
          DISPLAYSURF.fill(BGCOLOR)  
          drawBoard(mainBoard, revealedBoxes)
  
          for event in pygame.event.get():  
              if event.type == QUIT or (event.type == KEYUP and event.key == K_SPACE):
                  pygame.quit()
                  sys.exit()
              elif event.type == MOUSEMOTION:
                  mousex, mousey = event.pos
              elif event.type == MOUSEBUTTONUP:
                  mousex, mousey = event.pos
                  mouseClicked = True
              elif event.type == KEYUP and event.key == K_UP:
                 
                  mainBoard = getRandomizedBoard()
                  revealedBoxes = generateRevealedBoxesData(False)
  
             
                  drawBoard(mainBoard, revealedBoxes)
                  pygame.display.update()
                  pygame.time.wait(1000)
  
                
                  startGameAnimation(mainBoard)
  
          boxx, boxy = getBoxAtPixel(mousex, mousey)
          if boxx  != None and boxy != None:
             
              if not revealedBoxes[boxx][boxy]:
                  drawHighlightBox(boxx, boxy)
              if not revealedBoxes[boxx][boxy] and mouseClicked:
                  revealBoxesAnimation(mainBoard, [(boxx, boxy)])
                  revealedBoxes[boxx][boxy] = True 
                  if firstSelection == None:  
                      firstSelection = (boxx, boxy)
                  else:  
                    
                      icon1shape, icon1color = getShapeAndColor(mainBoard, firstSelection[0], firstSelection[1])
                      icon2shape, icon2color = getShapeAndColor(mainBoard, boxx, boxy)
  
                      if icon1shape != icon2shape or icon1color != icon2color:
                         
                          pygame.time.wait(1000)  
                          coverBoxesAnimation(mainBoard, [(firstSelection[0], firstSelection[1]), (boxx, boxy)])
                          revealedBoxes[firstSelection[0]][firstSelection[1]] = False
                          revealedBoxes[boxx][boxy] = False
                      elif hasWon(revealedBoxes): 
                          gameWonAnimation(mainBoard)
                          pygame.time.wait(1000)
  
                      firstSelection = None 
  
  def generateRevealedBoxesData(val):
      revealedBoxes = []
      for i in range(BOARDWIDTH):
          revealedBoxes.append([val] * BOARDHEIGHT)
      return revealedBoxes
  
  
  def getRandomizedBoard():
      
      icons = []
      for color in ALLCOLORS:
          for shape in ALLSHAPES:
              icons.append((shape, color))
  
      random.shuffle(icons)  
      numIconsUsed = int(BOARDWIDTH * BOARDHEIGHT / 2) 
      icons = icons[:numIconsUsed] * 2  
      random.shuffle(icons)
  
     
      board = []
      for x in range(BOARDWIDTH):
          column = []
          for y in range(BOARDHEIGHT):
              column.append(icons[0])
              del icons[0]  
          board.append(column)
      return board
  
  
  def splitIntoGroupsOf(groupSize, theList):
      
      result = []
      for i in range(0, len(theList), groupSize):
          result.append(theList[i:i + groupSize])
      return result
  
  
  def leftTopCoordsOfBox(boxx, boxy):
      
      left = boxx * (BOXSIZE + GAPSIZE) + XMARGIN
      top = boxy * (BOXSIZE + GAPSIZE) + YMARGIN
      return (left, top)
  
  
  def getBoxAtPixel(x, y):
      for boxx in range(BOARDWIDTH):
          for boxy in range(BOARDHEIGHT):
              left, top = leftTopCoordsOfBox(boxx, boxy)
              boxRect = pygame.Rect(left, top, BOXSIZE, BOXSIZE)
              if boxRect.collidepoint(x, y):
                  return (boxx, boxy)
      return (None, None)
  
  
  def drawIcon(shape, color, boxx, boxy):
      quarter = int(BOXSIZE * 0.25)  
      half = int(BOXSIZE * 0.5)  
  
      left, top = leftTopCoordsOfBox(boxx, boxy)  
      
      if shape == DONUT:
          pygame.draw.circle(DISPLAYSURF, color, (left + half, top + half), half - 5)
          pygame.draw.circle(DISPLAYSURF, BGCOLOR, (left + half, top + half), quarter - 5)
      elif shape == SQUARE:
          pygame.draw.rect(DISPLAYSURF, color, (left + quarter, top + quarter, BOXSIZE - half, BOXSIZE - half))
      elif shape == DIAMOND:
          pygame.draw.polygon(DISPLAYSURF, color, (
          (left + half, top), (left + BOXSIZE - 1, top + half), (left + half, top + BOXSIZE - 1), (left, top + half)))
      elif shape == LINES:
          for i in range(0, BOXSIZE, 4):
              pygame.draw.line(DISPLAYSURF, color, (left, top + i), (left + i, top))
              pygame.draw.line(DISPLAYSURF, color, (left + i, top + BOXSIZE - 1), (left + BOXSIZE - 1, top + i))
      elif shape == OVAL:
          pygame.draw.ellipse(DISPLAYSURF, color, (left, top + quarter, BOXSIZE, half))
  
  
  def getShapeAndColor(board, boxx, boxy):
      
      return board[boxx][boxy][0], board[boxx][boxy][1]
  
  
  def drawBoxCovers(board, boxes, coverage):
      
      for box in boxes:
          left, top = leftTopCoordsOfBox(box[0], box[1])
          pygame.draw.rect(DISPLAYSURF, BGCOLOR, (left, top, BOXSIZE, BOXSIZE))
          shape, color = getShapeAndColor(board, box[0], box[1])
          drawIcon(shape, color, box[0], box[1])
          if coverage > 0:  
              pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, coverage, BOXSIZE))
      pygame.display.update()
      FPSCLOCK.tick(FPS)
  
  
  def revealBoxesAnimation(board, boxesToReveal):
      
      for coverage in range(BOXSIZE, (-REVEALSPEED) - 1, -REVEALSPEED):
          drawBoxCovers(board, boxesToReveal, coverage)
  
  
  def coverBoxesAnimation(board, boxesToCover):
      
      for coverage in range(0, BOXSIZE + REVEALSPEED, REVEALSPEED):
          drawBoxCovers(board, boxesToCover, coverage)
  
  
  def drawBoard(board, revealed):
      
      for boxx in range(BOARDWIDTH):
          for boxy in range(BOARDHEIGHT):
              left, top = leftTopCoordsOfBox(boxx, boxy)
              if not revealed[boxx][boxy]:
                 
                  pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, BOXSIZE, BOXSIZE))
              else:
                 
                  shape, color = getShapeAndColor(board, boxx, boxy)
                  drawIcon(shape, color, boxx, boxy)
  
  
  def drawHighlightBox(boxx, boxy):
      left, top = leftTopCoordsOfBox(boxx, boxy)
      pygame.draw.rect(DISPLAYSURF, HIGHLIGHTCOLOR, (left - 5, top - 5, BOXSIZE + 10, BOXSIZE + 10), 4)
  
  
  def startGameAnimation(board):
      
      coveredBoxes = generateRevealedBoxesData(False)
      boxes = []
      for x in range(BOARDWIDTH):
          for y in range(BOARDHEIGHT):
              boxes.append((x, y))
      random.shuffle(boxes)
      boxGroups = splitIntoGroupsOf(8, boxes)
  
      drawBoard(board, coveredBoxes)
      for boxGroup in boxGroups:
          revealBoxesAnimation(board, boxGroup)
          coverBoxesAnimation(board, boxGroup)
  
  
  def gameWonAnimation(board):
      
      coveredBoxes = generateRevealedBoxesData(True)
      color1 = LIGHTBGCOLOR
      color2 = BGCOLOR
  
      for i in range(13):
          color1, color2 = color2, color1  
          DISPLAYSURF.fill(color1)
          drawBoard(board, coveredBoxes)
          pygame.display.update()
          pygame.time.wait(300)
  
      pygame.init()
      myfont = pygame.font.Font(None, 60)
      textImage = myfont.render("PRESS UP TO RESTART", True, SKYBLUE)
      DISPLAYSURF.fill(SNOW)
      DISPLAYSURF.blit(mao,(20,0))
      DISPLAYSURF.blit(textImage, (50, 100))
      pygame.display.update()
  
  def hasWon(revealedBoxes):
      
      for i in revealedBoxes:
          if False in i:
              return False  
      return True
  
  
  if __name__ == '__main__':
      main()
  