[Richard Suchenwirth] 2003-07-04 – In a brief Wiki visit during vacations, I noticed [A simple memory game], "downloaded" and played it a bit - and wanted to do an alternative implementation, with distinctive colors and shapes for easier memorization. Here it is: [WikiDbImage memory.jpg] (Screenshot in Cheat mode - normally you see at most two cards exposed.) ====== set about "Memory2 R.Suchenwirth 2003 Tap on two cards to turn them over. If they are equal, you win them (10 score). Else they are turned back again (-1 score). Click Cheat to see all for a second." package require Tk proc main {} { frame .f label .f.s -text Score: label .f.l -textvariable g(score) -width 4 -bg white button .f.a -text About -command {tk_messageBox -message $about} button .f.n -text New -command {reset .c} tk_optionMenu .f.m g(pairs) 8 10 12 15 button .f.c -text Cheat -command {.c lower cover; #after 1000 .c raise cover} button .f.x -text X -command exit eval pack [winfo childr .f] -side left -fill y canvas .c -bg darkgreen -height 250 pack .f .c -fill x initCards reset .c } ====== Card images are described in a [little language]: first the background color, then any number of items in the sequence: type (rect or poly) - fill color - relative coordinates (between 0 and 1): ====== proc initCards {} { global g array set g { c.1 {red rect white {.2 .4 .8 .6} rect white {.4 .2 .6 .8}} c.2 green c.3 {blue rect yellow {0 .33 1 .66}} c.4 {yellow poly red {0 0 0 1 1 1}} c.5 {purple poly white {.5 0 0 .5 .5 1 1 .5} poly yellow {.5 .2 .2 .5 .5 .8 .8 .5}} c.6 {white rect blue {0 0 .32 1} rect red {.68 0 1 1}} c.7 {white rect black {0 .5 .5 1} rect black {.5 0 1 .5}} c.8 {black poly green {.1 .8 .5 .2 .9 .8}} c.9 {lightblue poly red {.1 .1 .9 .1 .5 .9} poly white {.3 .25 .7 .25 .5 .65}} c.10 {black rect red {0 .33 1 .67} rect yellow {0 .67 1 1}} c.11 {yellow rect black {.3 0 1 .7}} c.12 {blue poly yellow {0 0 0 .8 .8 0} poly yellow {.2 1 1 .2 1 1}} c.13 {blue rect white {.2 .2 .8 .4} rect white {.2 .6 .8 .8}} c.14 {black poly red {0 0 1 0 .5 .5} poly red {0 1 1 1 .5 .5}} c.15 {white rect purple {.1 .1 .9 .3} rect purple {.4 .1 .6 .9}} } foreach card [array names g c.*] { lappend g(cards) $card $card } } ====== Shuffle and arrange cards on "table": ====== proc reset w { global g set g(seen) {} set g(score) 0 $w delete all set n [expr {2*$g(pairs)-1}] set ncol [expr {$n<17? 4: 5}] set cards [lrange $g(cards) 0 $n] for {set i 0} {$i<6} {incr i} { for {set j 0} {$j<$ncol} {incr j} { if ![llength $cards] break putCard $w $i $j [ldraw cards] } } $w bind cover <1> "uncover $w" } proc uncover w { global g set id [$w find withtag current] set which [lindex [$w gettags $id] 1] $w lower $id ;# show card lappend g(seen) $which if {[llength $g(seen)]==2} { compare $w $g(seen) set g(seen) {} } } ====== Two cards are open - see whether they show the same picture: ====== proc compare {w seen} { global g update after 1000 ;#wait for player to look foreach {first second} $seen break if {$g($first)==$g($second)} { eval $w delete $seen incr g(score) 10 } else { $w raise cover incr g(score) -1 } } ====== This computes the bounding box for a card, and has it drawn: ====== proc putCard {w row col img} { global g set s [expr {$g(pairs)<9? 45: $g(pairs)<13? 38: 33}] set d [expr {$g(pairs)<9? 10: 7}] set x0 [expr {$col*($s+$d)+$d}] set x1 [expr {$x0+$s}] set y0 [expr {$row*($s+$d)+$d}] set y1 [expr {$y0+$s}] card $w $x0 $y0 $x1 $y1 $g($img) $col.$row set g($col.$row) $img } ====== This executes the little "card description language", by scaling and translating relative coordinates to absolute ones: ====== proc card {w x0 y0 x1 y1 img tag} { $w create rect $x0 $y0 $x1 $y1 -fill [lindex $img 0] -tag $tag set dx [expr {$x1 - $x0 - 2}] foreach {type color coords} [lrange $img 1 end] { set final {} foreach {x y} $coords { lappend final [expr {$x0+$x*$dx+1}] lappend final [expr {$y0+$y*$dx+1}] } $w create $type $final -fill $color -outline $color -tag $tag } $w create rect $x0 $y0 $x1 $y1 -fill grey -tag "cover $tag" } ====== Random arrangement of cards is done by picking and removing an arbitrary element from the list: ====== proc ldraw varName { upvar 1 $varName v set pos [expr {int(rand()*[llength $v])}] K [lindex $v $pos] [set v [lreplace $v $pos $pos]] } proc K {a b} {set a} #----------------------- Let's go! main wm geometry . 236x270+0+0 ;# iPaq ====== ---- [Kroc] revealed a bug that the default canvas is too small on Linux to show the 6th on row with 15 pairs. Added explicit canvas height - [RS] ---- [Kroc] - 05 Oct 2004 : I've done a '''Famous Tcl'ers edition''' of this game (featuring Donal Fellows, Jeff Hobbs, Richard Suchenwirth, Jean-Claude Wippler, Arjen Markus, Steve Landers, Kevin Kenny, Reinhard Max, John Ousterhout, Andreas Kupries, Miguel Sofer, Don Porter, Brent Welch, Larry Virden and David Welton): http://www.kroc.tk/fichiers/Memory2k.tcl [http://www.kroc.tk/fichiers/Memory2k.png] [HJG] 2013-10-10: The link above to Kroc's game had changed. <> Games