Lingo Game: Memory

Play "memory_game"

In this classical game, an even number of cards are arranged face-down on a table in a rectangular fashion. One or more player(s) take turns flipping pairs of cards.

If they happen to match, it is a win for the player who turned them over. Then the cards stay open (or removed from the table).
If they do not match, they are flipped back over.

We will be discussing how to create a prototype of such a game with 8 cards and a single player (puzzle). The computer facilitates the playing.

We need to come up first with the data structures that will hold the information of the cards, and with pseudocode that will capture the game's mechanics.

Data Structures

We will use a list to keep track of the cards. We have placed cards in the first few entries of the cast, and for this prototype we will use cards in positions 1-4. Note that there is a blank card in position 51 which will serve as the generic card to flip.

It makes sense the initialization to happen in the preparatory frame or when we click the "New Game" button:

```   -- assume 8 blank cards are placed in sprites (channels) 1-8
totalCards = 8
-- create a list  of totalCards/2 pairs of cards
cardList = list()
cardList = [1,1,2,2,3,3,4,4] -- they need to be shuffled```

To start a game we will need to shuffle the cards.

Shuffling the cards

To create the effect of a shuffle, we need to be able to create a random list of pairs of numbers between 1 and half-the-number-of-cards on the table.

The easiest way would be to scramble them! We can start with the non-sorted cardList and then permute their order by repeatedly removing a random one and placing it into a new pile called aftershuffle.

```on shuffleCards
global cardList, totalCards
aftershuffle = []  -- another way to create an empty list
repeat while count(cardList) > 0
pick = random(count(cardList))  -- pick a random card
symbol = getAt(cardList, pick)  -- find out which its symbol is
deleteAt cardList, pick         -- remove it from the cardList
append aftershuffle, symbol     -- and place it in the new list
end repeat
cardList = aftershuffle     -- the new list becomes our shuffled cardList
end```

After executing shuffleCards, we are ready to start a game!

The pseudocode

A card is selected for flipping by clicking on in. So, it makes sense to create a handler only on the cast member of the unflipped card (the blank card in position 51). (Why?)

Here is in pseudocode what should happen:

``` on mouseUp
if it is the first card to be flipped then
flip it -- find out which its symbol is
remember its symbol
else -- if it is the second card flipped in this turn
flip it -- find out which its symbol is
check whether its symbol matches the previous card's symbol
end if
end```

We need to resolve the following problems:
1. How do we remember the card symbols?
2. How do we find out which symbol was picked?
3. How do we check for match?

1. How do we remember the card symbols?

To remember the card symbols between flips, we can simply use a couple of global variables, called card1 and card2 which are initialized at the beginning of the game to 0 and are reset at the end of every turn. The player can select for card1 and card2 any of the cards we have arranged on the table. It makes sense this to happen in a frame prior to the one playing the game since we may want to replay the game again and again.

```-- Prepare for a new game
on exitFrame me
global card1, card2
card1 = 0     -- Note: 0 means "no card chosen yet"
card2 = 0
-- Also initialize your data structures as explained above
end```
2. How do we find out which symbol was picked?

To find out which symbol was picked we need to see which blank card the user clicked on, and find the corresponding number from the cardList.

```   card1 = the Clickon                -- Returns the channel number (1-8) of a selected card
sprite(card1).member = cardList[card1]  -- Array-like code for cardList.getAt(card1)```

3. How do we check for match?

To check for a match between cards we need to see if their symbols match. If they do, fine, give them some feedback via audio to that effect. If not, we need to flip them back and prepare for the next turn. Which means: make card1 and card2 be again 0.

```on checkForMatch c1, c2
global card1, card2
if c1 = c2 then   -- Play a sound to give feedback
sound(1).queue(member "Match Sound")
sound(1).play()       -- and leave the cards on
else              -- Play a different sound for feedback
sound(1).queue(member "No Match Sound")
sound(1).play()
-- Not a match, turn the cards back to blank
sprite(card1).member = 51 -- Remember that 51 is the blank card
sprite(card2).member = 51
end if
-- prepare for another round of the game
card1 = 0
card2 = 0
end```

So, the code on the blank card now is:

```on mouseUp me
global card1, card2, cardList

if card1 = 0 then -- it was the first card of the pair to be clicked
card1 = the Clickon
sprite(card1).member = cardList[card1]
else
card2 = the ClickOn
sprite(card2).member = cardList[card2]
-- anything else?
end if
end```

This almost works. Because of the speed of the program flipping cards, the user will not be able to see what the second card is before it is flipped back. (For the first card there is no problem, because we are waiting for the user action.) We need to give the user time to see the second card. We can do that by initializing a timer

`       myTimer = the ticks `

in the no-match case wait before flipping back for one second. (Note: You just introduced a new variable...)

Who will check whether the timer is done? The best place to do this done is to put the code for waiting in the game frame. (Having a repeat doing nothing will not work because the optimizing compiler will ignore it. I can hear the compiler saying: "You eventually want it to turn to blank, let me do it for you...")

```-- Game frame
on exitFrame me  global card1, card2, cardList, myTimer  waitingTime = 60   -- That is: 1 sec = 60 ticks  if myTimer + waitingTime < the ticks then -- Time passed    if card2 <>0 then checkForMatch cardList[card1], cardList[card2]  end if     go to the frameend
```
The rest

That's it. Well, almost.

• We may need to detect when all cards have been flipped and declare the end of the game. How would you do it?
• You may need to try to have a game with 16 cards, how would you do that?
• You might want to make it more challenging by having an on-screen timer telling the player how long did it take them to solve the puzzle. But not too challenging!
• You may want to change the game to have 2 levels, easy (as is) and tough (with 16 cards).
• You may want to be able to save a game to finish later.
• You may also need to make this a 2-player game, where players take turns flipping cards and the one with the most pairs wins. That's a little more challenging. How would you do that?

Achnowledgements

The game idea and images used were taken from Gary Rosenzweig's Advanced Lingo for Games

Maintained By: Takis Metaxas