Random Shuffle Memory Match
March 14, 1999
by Pat McClellan
Dear Multimedia Handyman,
I've been "noodling" with your memory game code and I need to make some modifications. I want to be able to have the cards shuffle themselves so they are a random set of 6 matched pairs, and then using some kind of a swap to place them at a certain locH and locV. Can you help?
Confused in Canada
Dear Confused in Canada,
This is a great addition to the behavior. Let's start by reviewing the original behavior. You drop it on the sprites representing the "backs" of the cards to be "flipped". When you drop it on there, you can specify the front (which is stored in a property called pFront.) The rest of the behavior handles swapping the "front" and "back" when they're clicked -- as well as tracking whether it's a match.
-- MatchGame behavior
-- Used to set up pairs of matching sprites
property pMyID -- matching pairs will have the same ID
property pMySpriteNum
property pFront -- the "front" of the card
property pBack -- the "back" of the card
property pSelected -- state of the card, selected/not
property pLocH
global gSpritesMatched
on getPropertyDescriptionList
set pmySpriteNum = the currentSpriteNum
if pMySpriteNum = 0 then
set memdefault = 0
else
set memref = the member of sprite pMySpriteNum
set castlibnum = the castlibnum of memref
set memDefault = member (the membernum of ¬
member memref + 1) of castlib castlibnum
end if
set p_list = [#pMyID: [ #comment:"ID:", #format: ¬
#symbol, #default: #item1 ], #pFront:[ ¬
#comment:"Member:", #format: #graphic, ¬
#default: memDefault] ]
return p_list
end
on beginSprite me
set pMySpriteNum = the spriteNum of me
-- put "Sprite" && pMySpriteNum && "is" ¬
&& pMyID && pFront
set pSelected = FALSE
set pBack = the member of sprite pMySpriteNum
set pLocH = the locH of sprite pMySpriteNum
end
on mouseUp me
set pSelected = TRUE
set the member of sprite pMySpriteNum to pFront
updateStage
sendAllSprites(#checkMatch, pMyID, pMySpriteNum)
end
on checkMatch me, testID, testSpriteNum
if pSelected = TRUE AND testSpriteNum <> ¬
pMySpriteNum then
if testID = pMyID then
beep
startTimer
repeat while the timer < 60 -- delay
end repeat
makeMatch me
sendSprite(testSpriteNum, #makeMatch)
else
beep
startTimer
repeat while the timer < 60 -- delay
end repeat
flipBack me
sendSprite(testSpriteNum, #flipBack)
end if
end if
end
on makeMatch me
-- do whatever you want
set the locH of sprite pMySpriteNum to 800
set pSelected = FALSE
set gSpritesMatched = gSpritesMatched + 1
end
on flipBack me
-- play annoying sfx if desired
set the member of sprite pMySpriteNum to pBack
set pSelected = FALSE
end
on reset me
set the member of sprite pMySpriteNum to pBack
set the locH of sprite pMySpriteNum to pLocH
end
Now the part you want to add is, essentially, randomizing the values for pFront. If we just add a handler to the bottom of this behavior, you'll still be asked to specify a front when you drop it on the sprite, but that can easily be over-ridden when you want to reset the game.
What we'll need to do is create two property lists of the possible castmembers that could be assigned to the cards, along with an "item ID number" so that we'll know which ones match. This item ID is important because you might want to assign 2 different cast members as a pair -- different cast members with the same item ID. For this demo, I set these lists up in the resetGame movie script:
on resetGame
global gSpritesMatched
set gSpritesMatched = 0
sendAllSprites (#reset)
set cardList1 = [#item1:(member 3 of castLib 1), ¬
#item2:(member 4 of castLib 1), #item3:(member 5 ¬
of castLib 1), #item4:(member 6 of castLib 1), ¬
#item5:(member 7 of castLib 1), #item6:(member 8 ¬
of castLib 1)]
set cardList2 = [#item1:(member 3 of castLib 1), ¬
#item2:(member 4 of castLib 1), #item3:(member 5 of ¬
castLib 1), #item4:(member 6 of castLib 1), ¬
#item5:(member 7 of castLib 1), #item6:(member 8 ¬
of castLib 1)]
sendAllSprites(#randomizeCards, cardList1, cardList2)
end
This handler starts by resetting all the sprites to their original positions. Next, I create my two cardLists; in this case, they are identical because I'm using the same castmembers as pairs. NOTE: you can't simply say "set cardList2 = cardList1". It will screw it up. If you're looking for a shortcut, you have to say...
set cardList = duplicate(cardList1)
The reason is that if you just say set cardList2 = cardList1, it doesn't create a copy, but rather just a pointer to cardList1. That means if you delete something from cardList2, it really would get deleted from cardList1. Not good for our purposes.
The last step of the resetGame handler is to send out the message to all sprites to "randomizeCards". That's the new handler that will be added to the existing behavior:
-- add to bottom of Matchgame behavior
on randomizeCards me, cardList1, cardlist2
set count1 = count(cardList1)
set count2 = count(cardList2)
if count1 = 0 and count2 = 0 then
exit
else if count1 = 0 then
set myList = cardList2
else if count2 = 0 then
set myList = cardList1
else
put "random assignment"
case random(2) of
1: set myList = cardList1
2: set myList = cardList2
end case
end if
set cardsLeft = count(myList)
set whichCard = random(cardsLeft)
set pFront = getAt(myList, whichCard)
set pMyID = getPropAt(myList, whichCard)
deleteProp myList, pMyID
end
Most of this handler is dedicated to choosing an item from one of the lists at random. You can analyze the logic if you really have the time. Once that's decided, the itemID and pFront castmember are assigned, and then that selection is deleted from the list to avoid duplication. (This is the delete part that would screw us up if we hadn't made a duplicate of the list.)
That's the way it works. Download the code if you want to check under the hood (Mac or PC).
Copyright 1997-2025, Director Online. Article content copyright by respective authors.