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-2024, Director Online. Article content copyright by respective authors.