Memory Source Code – Programming 1 Final

Welcome back to my journey of my Programming 1 Final. After finding out what I was going to do for the base, I had to completely learn how to use Pygame and now you can get a look at just how my program is set up before presenting the final project and all of the glory that it brings.


My final program does not use any outside files in which I have written nor does it include any text files or sound files. This ReadMe file will help explain how to download and what to import in order to run the program.

Source Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#
# Adrianna Rodencal
#
# Final Project for Programming 1
# Simon Memory Game
#
# Started: 12/3/19
# Last Updated: 12/21/19
#
import random, sys, time, pygame
from pygame.locals import *

FPS = 30
WINDOWWIDTH = 640
WINDOWLENGTH = 480
FLASHSPEED = 500
FLASHDELAY = 200
FPSCLOCK = pygame.time.Clock()
BUTTONSIZE = 200
BUTTONGAPSIZE = 20
DISPLAYSURF = pygame.display.set_mode((WINDOWLENGTH, WINDOWWIDTH))
TIMEOUT = 5
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BRIGHTRED = (255, 0, 0)
RED = (155, 0, 0)
BRIGHTGREEN = (0, 255, 0)
GREEN = (0, 155, 0)
BRIGHTBLUE = (0, 0, 255)
BLUE = (0, 0, 155)
BRIGHTYELLOW = (255, 255, 0)
YELLOW = (155, 155, 0)
bgColor = BLACK

XMARGIN = int((WINDOWWIDTH - (2 * BUTTONSIZE) - BUTTONGAPSIZE) /2)
YMARGIN = int((WINDOWLENGTH - (2 * BUTTONSIZE) - BUTTONGAPSIZE) /2)

YELLOWRECT = pygame.Rect(XMARGIN, YMARGIN, BUTTONSIZE, BUTTONSIZE)
BLUERECT = pygame.Rect(XMARGIN + BUTTONSIZE + BUTTONGAPSIZE, YMARGIN, BUTTONSIZE, BUTTONSIZE)
REDRECT = pygame.Rect(XMARGIN, YMARGIN + BUTTONSIZE + BUTTONGAPSIZE, BUTTONSIZE, BUTTONSIZE)
GREENRECT = pygame.Rect(XMARGIN + BUTTONSIZE + BUTTONGAPSIZE, YMARGIN + BUTTONSIZE + BUTTONGAPSIZE, BUTTONSIZE, BUTTONSIZE)

This is the first section of my program. Here I am labeling all of the things that I will need before I even start main(). We call these universals and they are often noted by being in all CAPITAL letters. It’s not recommended to use these every time that you do a program but for something like this where I am constantly updating my game board and using colors in many of my procedures I have made the colors and rectangle size universal to make things a little easier.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def main():
    global FPSCLOCK, DISPLAYSURF, BASICFONT
    pygame.init()
    pygame.font.init()
    basicFont = pygame.font.SysFont('Times New Romans', 20, False, False)
    size = (WINDOWWIDTH, WINDOWLENGTH)
    screen = pygame.display.set_mode(size)
    pygame.display.set_caption('Memory')
    infoSurf = basicFont.render('Click on the buttons that flash, in the order that they flash to level up.', 1, WHITE)
    infoLocation = (10, WINDOWLENGTH - 25)
    screen.blit(infoSurf, infoLocation)
    pygame.display.update()
    clock = pygame.time.Clock()
    print_instructions()
    gameData = init_game_data()
    computerPattern = []
    currentButton = 0
    score = 0
    inputWait = False
    while True:
        clickedButton = None
        DISPLAYSURF.fill(bgColor)
        drawButtons()
        scoreSurf = basicFont.render('Score: ' +str(score), 1, WHITE)
        scoreLocation = (WINDOWWIDTH - 100, 10)
        DISPLAYSURF.blit(scoreSurf, scoreLocation)
        DISPLAYSURF.blit(infoSurf, infoLocation)
        clickedButton = event_handler(pygame, clickedButton)
        if inputWait == False:
            pygame.display.update()
            pygame.time.wait(1000)
            computerPattern.append(random.choice((YELLOW, BLUE, RED, GREEN)))
            for button in computerPattern:
                buttonFlash(button)
                pygame.time.wait(FLASHDELAY)
            inputWait = True
        else:
            if clickedButton and clickedButton == computerPattern[currentButton]:
                buttonFlash(clickedButton)
                currentButton += 1
                lastClickTime = time.time()
                if currentButton == len(computerPattern):
                    score += 1
                    inputWait = False
                    currentButton = 0
            elif (clickedButton and clickedButton != computerPattern[currentButton]) or (currentButton!= 0 and time.time() - TIMEOUT > lastClickTime):
                gameOver()
                #newRound = new_game('Would you like to play again?', basicFont)
                computerPattern = []
                currentButton = 0
                inputWait = False
                score = 0
                pygame.time.wait(1000)
    pygame.display.update()
    FPSCLOCK.tick(FPS)
                            

def print_instructions():
    print('''
Welcome to the wonderful game of Memory!! (I know, very creative title).
The game will start in a few short moments. Watch carefully and
try to remember the pattern of the flashing buttons.
Good Luck!''')
    

def init_game_data():
    BASICFONT = pygame.font.Font('freesansbold.ttf', 16)
    infoSurf = BASICFONT.render('Hello', 1, YELLOW)
    infoRect = infoSurf.get_rect()
    infoRect.topleft = (10, WINDOWLENGTH - 25)
    
    pygame.display.update()

def event_handler(pygame, clickedButton):
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouseX, mouseY = event.pos
            clickedButton = getButtonClicked(mouseX, mouseY)
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                clickedButton = YELLOW
            elif event.key == pygame.K_w:
                clickedButton = BLUE
            elif event.key == pygame.K_a:
                clickedButton = RED
            elif event.key == pygame.K_s:
                clickedButton = GREEN
    return clickedButton

Here you can see my main(), print_instructions(), init_game_data(), and event_handler(). These procedures are the base of the program. The main obviously being the core that tells the computer in what order to everything but the event_handler() goes through and checks to see if any buttons have been clicked. This allows for the game screen to be interactive with the user and allows later for graphics to also work.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
def terminate():
    pygame.quit()
    sys.exit()

def userQuit():
    for event in pygame.event.get(QUIT):
        terminate()
    for event in pygame.event.get(KEYUP):
        if event.key == K_ESCAPE:
            terminate()
        pygame.event.post(event)

def buttonFlash(color, animationSpeed = 50):
    if color == YELLOW:
        flashColor = BRIGHTYELLOW
        rectangle = YELLOWRECT
    elif color == BLUE:
        flashColor = BRIGHTBLUE
        rectangle = BLUERECT
    elif color == RED:
        flashColor = BRIGHTRED
        rectangle = REDRECT
    elif color == GREEN:
        flashColor = BRIGHTGREEN
        rectangle = GREENRECT

    originalSurf = DISPLAYSURF.copy()
    flashSurf = pygame.Surface((BUTTONSIZE, BUTTONSIZE))
    flashSurf = flashSurf.convert_alpha()
    r, g, b = flashColor
    for start, end, step in((0, 255, 1), (255, 0, -1)):
        for alpha in range(start, end, animationSpeed*step):
            userQuit()
            DISPLAYSURF.blit(originalSurf, (0, 0))
            flashSurf.fill((r, g, b, alpha))
            DISPLAYSURF.blit(flashSurf, rectangle.topleft)
            pygame.display.update()
            FPSCLOCK.tick(FPS)
    DISPLAYSURF.blit(originalSurf, (0, 0))

def drawButtons():
    pygame.draw.rect(DISPLAYSURF, YELLOW, YELLOWRECT)
    pygame.draw.rect(DISPLAYSURF, BLUE, BLUERECT)
    pygame.draw.rect(DISPLAYSURF, RED, REDRECT)
    pygame.draw.rect(DISPLAYSURF, GREEN, GREENRECT)

def gameOver(color = WHITE, animationSpeed = 50):
    origSurf = DISPLAYSURF.copy()
    flashSurf = pygame.Surface(DISPLAYSURF.get_size())
    flashSurf = flashSurf.convert_alpha()
    r, g, b = color
    for i in range(3): # do the flash 3 times
        for start, end, step in ((0, 255, 1), (255, 0, -1)):
            # The first iteration in this loop sets the following for loop
            # to go from 0 to 255, the second from 255 to 0.
            for alpha in range(start, end, animationSpeed * step): # animation loop
                # alpha means transparency. 255 is opaque, 0 is invisible
                userQuit()
                flashSurf.fill((r, g, b, alpha))
                DISPLAYSURF.blit(origSurf, (0, 0))
                DISPLAYSURF.blit(flashSurf, (0, 0))
                basicFont = pygame.font.SysFont('Times New Romans', 30, False, False)
                gameOver = basicFont.render('GAME OVER', 1, WHITE)
                endLocation = (255,0)
                DISPLAYSURF.blit(gameOver, endLocation)
                drawButtons()
                pygame.display.update()
                FPSCLOCK.tick(FPS)

def getButtonClicked(x, y):
    if YELLOWRECT.collidepoint((x, y)):
        return YELLOW
    elif BLUERECT.collidepoint((x, y)):
        return BLUE
    elif REDRECT.collidepoint((x, y)):
        return RED
    elif GREENRECT.collidepoint((x, y)):
        return GREEN
    return None


if __name__ == '__main__':
    main()

The rest of these procedures all work with the small details that help make the game run smoothly, making sure the user hasn’t quit the game or checking to see that they are doing the correct pattern. If one of these smaller procedures goes off and the user gets something wrong the game will go to the gameOver() procedure before resetting for the next game.

Leave a Reply