Download MemoryPackage v2
'From Cuis7.3 [latest update: #7095] on 10 April 2025 at 10:56:43 am'! 'Description '! !provides: 'MemoryGameV2' 1 9! SystemOrganization addCategory: 'MemoryGameV2'! !classDefinition: #MemoryCardModel category: 'MemoryGameV2'! Object subclass: #MemoryCardModel instanceVariableNames: 'flipped done color' classVariableNames: '' poolDictionaries: '' category: 'MemoryGameV2'! !classDefinition: 'MemoryCardModel class' category: 'MemoryGameV2'! MemoryCardModel class instanceVariableNames: ''! !classDefinition: #MemoryGame category: 'MemoryGameV2'! Object subclass: #MemoryGame instanceVariableNames: 'model view playing' classVariableNames: '' poolDictionaries: '' category: 'MemoryGameV2'! !classDefinition: 'MemoryGame class' category: 'MemoryGameV2'! MemoryGame class instanceVariableNames: ''! !classDefinition: #MemoryGameModel category: 'MemoryGameV2'! Object subclass: #MemoryGameModel instanceVariableNames: 'size tupleSize cards' classVariableNames: '' poolDictionaries: '' category: 'MemoryGameV2'! !classDefinition: 'MemoryGameModel class' category: 'MemoryGameV2'! MemoryGameModel class instanceVariableNames: ''! !classDefinition: #MemoryGameWindow category: 'MemoryGameV2'! SystemWindow subclass: #MemoryGameWindow instanceVariableNames: 'presenter statusBar playground' classVariableNames: '' poolDictionaries: '' category: 'MemoryGameV2'! !classDefinition: 'MemoryGameWindow class' category: 'MemoryGameV2'! MemoryGameWindow class instanceVariableNames: ''! !MemoryGame commentStamp: '<historical>' prior: 0! I am the presenter of the Memory Game. I create the model of the game and I handle the user interaction.! !MemoryGameWindow commentStamp: '<historical>' prior: 0! A memory game based on finding identical squares of the same color.! !MemoryCardModel methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 13:14:16'! backColor ^ Color white! ! !MemoryCardModel methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 13:31:11'! color ^ color! ! !MemoryCardModel methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 13:31:11'! color: anObject color := anObject! ! !MemoryCardModel methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 13:30:03'! setDone done := true! ! !MemoryCardModel methodsFor: 'testing' stamp: 'hlsf 3/22/2025 13:30:12'! isDone ^ done! ! !MemoryCardModel methodsFor: 'testing' stamp: 'hlsf 3/22/2025 13:15:39'! isFlipped ^ flipped! ! !MemoryCardModel methodsFor: 'updating' stamp: 'hlsf 3/22/2025 19:40:34'! flip | newColor | flipped := flipped not. newColor := flipped ifTrue: [color ] ifFalse: [self backColor]. self triggerEvent: #color with: newColor! ! !MemoryCardModel methodsFor: 'updating' stamp: 'hlsf 3/22/2025 15:53:33'! flipFlash self flip. self triggerEvent: #flash! ! !MemoryCardModel methodsFor: 'initialization' stamp: 'hlsf 3/22/2025 13:28:57'! initialize super initialize. done := flipped := false! ! !MemoryGame methodsFor: 'callback ui' stamp: 'hlsf 3/29/2025 23:00:43'! flip: position | flippedCards | (model cards at: position) flip; triggerEvent: #lock. flippedCards := model flippedCards. " Do the flipped cards share the same color? " (flippedCards collect: [:aCard | aCard color]) asSet size = 1 ifFalse: [ " NO " " Some delay for the player to see the colors of these flipped cards " view message: 'Colors do not match!!'. view world doOneCycleNow. (Delay forSeconds: 1) wait. " Unflip and unlock the flipped cards " flippedCards do: [:aCard | aCard flip; triggerEvent: #flash; triggerEvent: #unlock]. ^ self]. flippedCards size = model tupleSize ifTrue: [ " We found a n-tuple!! " view message: 'Great!!' bold, ' You find a ', model tupleSize asString, '-tuple!!'. flippedCards do: [:aCard | aCard triggerEvent: #flash]. flippedCards do: #setDone. model isGameWon ifTrue: [ view message: 'Congratuluation, you finished the game!!' bold red. playing := false] ]! ! !MemoryGame methodsFor: 'callback ui' stamp: 'hlsf 3/22/2025 22:28:33'! startGame model installCardModels. view installCards. view message: 'Starting a new game' bold green. view setLabel: 'P L A Y I N G'. playing := true. ! ! !MemoryGame methodsFor: 'callback ui' stamp: 'hlsf 3/22/2025 22:27:53'! stopGame playing := false. view message: 'Game over'. view setLabel: 'G A M E S T O P P E D'. model undoneCards do: [:aCard | aCard triggerEvent: #flash; flip. view world doOneCycleNow]! ! !MemoryGame methodsFor: 'initialization' stamp: 'hlsf 3/22/2025 22:25:51'! initialize model := MemoryGameModel new. view := MemoryGameWindow presenter: self. self startGame. view openInWorld.! ! !MemoryGame methodsFor: 'testing' stamp: 'hlsf 3/22/2025 15:42:24'! isPlayed ^ playing ! ! !MemoryGame methodsFor: 'testing' stamp: 'hlsf 3/22/2025 15:42:35'! isStopped ^ self isPlayed not! ! !MemoryGame methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 22:07:58'! model ^model! ! !MemoryGameModel methodsFor: 'initialization' stamp: 'hlsf 3/22/2025 22:25:40'! initialize size := 4 @ 3. tupleSize := 2! ! !MemoryGameModel methodsFor: 'initialization' stamp: 'hlsf 3/22/2025 15:35:13'! installCardModels | colours | cards := Array2D newSize: size. colours := self distributeColors. 1 to: size y do: [:y | 1 to: size x do: [:x | cards at: x@y put: (MemoryCardModel new color: colours removeFirst) ] ]! ! !MemoryGameModel methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 15:55:08'! cards ^ cards! ! !MemoryGameModel methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 15:09:23'! distributeColors | colors | colors := OrderedCollection new. size x * size y / tupleSize timesRepeat: [colors add: Color random]. tupleSize - 1 timesRepeat: [colors := colors, colors]. ^ colors shuffled! ! !MemoryGameModel methodsFor: 'accessing' stamp: 'hlsf 4/10/2025 10:55:03'! doneCards ^ cards elements select: #isDone! ! !MemoryGameModel methodsFor: 'accessing' stamp: 'hlsf 4/10/2025 10:55:14'! flippedCards ^ cards elements select: [:aCard | aCard isDone not and: [aCard isFlipped] ]! ! !MemoryGameModel methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 15:55:16'! size ^ size! ! !MemoryGameModel methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 19:23:33'! tupleSize ^ tupleSize ! ! !MemoryGameModel methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 15:10:50'! undoneCards ^ cards elements asOrderedCollection removeAll: self doneCards; yourself.! ! !MemoryGameModel methodsFor: 'testing' stamp: 'hlsf 4/10/2025 10:54:49'! isGameWon ^ (cards elements select: #isDone) size = (size x * size y)! ! !MemoryGameWindow methodsFor: 'accessing' stamp: 'hlsf 3/15/2025 18:52:39'! adoptWidgetsColor: paneColor " Does nothing, let the buttons have their own colors "! ! !MemoryGameWindow methodsFor: 'accessing' stamp: 'hlsf 3/16/2025 17:16:57'! message: aText statusBar contents: aText ; redrawNeeded ! ! !MemoryGameWindow methodsFor: 'accessing' stamp: 'hlsf 3/22/2025 15:38:00'! presenter: aPresenter presenter := aPresenter. self model: presenter model! ! !MemoryGameWindow methodsFor: 'initialization' stamp: 'hlsf 3/22/2025 22:25:57'! initialize super initialize. playground := LayoutMorph newColumn. self installToolbar. self addMorph: playground. self installStatusBar ! ! !MemoryGameWindow methodsFor: 'initialization' stamp: 'hlsf 3/22/2025 22:18:57'! installCards | row size | playground removeAllMorphs. size := model size. 1 to: size y do: [:y | row := LayoutMorph newRow. 1 to: size x do: [:x | | cardModel cardView | cardModel := model cards at: x@y. cardView := PluggableButtonMorph model: presenter action: #flip: actionArgument: x@y. cardModel when: #color send: #color: to: cardView; when: #lock send:#lock to: cardView; when: #unlock send: #unlock to: cardView; when: #flash send: #flash to: cardView. cardView layoutSpec proportionalWidth: 1; proportionalHeight: 1. cardView color: cardModel backColor. row addMorph: cardView]. playground addMorph: row ]! ! !MemoryGameWindow methodsFor: 'initialization' stamp: 'hlsf 3/18/2025 23:14:00'! installStatusBar statusBar := TextParagraphMorph new padding: 2; color: Color transparent; borderWidth: 1; borderColor: self borderColor twiceLighter ; setHeightOnContent. self addMorph: statusBar layoutSpec: LayoutSpec new useMorphHeight. self message: 'Welcome to ', 'Memory Game' bold! ! !MemoryGameWindow methodsFor: 'initialization' stamp: 'hlsf 3/22/2025 15:40:23'! installToolbar | toolbar button | toolbar := LayoutMorph newRow separation: 2. button := PluggableButtonMorph model: presenter action: #startGame :: enableSelector: #isStopped; icon: Theme current playIcon; borderWidth: 2; borderColor: Color black; setBalloonText: 'Play the game'; morphExtent: 32 asPoint. toolbar addMorph: button. button := PluggableButtonMorph model: presenter action: #stopGame :: enableSelector: #isPlayed; icon: Theme current stopIcon; setBalloonText: 'Stop the game'; morphExtent: 32 asPoint. toolbar addMorph: button. self addMorph: toolbar layoutSpec: LayoutSpec new useMorphHeight ! ! !MemoryGameWindow class methodsFor: 'instance creation' stamp: 'hlsf 3/22/2025 15:37:23'! presenter: aPresenter ^ self basicNew presenter: aPresenter ; initialize ; yourself! !