Version 2 of A simple memory game

Updated 2003-07-02 11:08:22

Arjen Markus Inspired by RS's A funny cookbook I wrote down this script that implements a very basic memory game. In Holland it is actually known as "Memory" - I do not know whether that is the proper English name, though.

The rules are simple: you have a number of pairs of cards and they are put on the table, face down. Each player turns around two of the cards and if he/she has a matching pair, he/she gets them. The winner is of course the player with most pairs.

The script below implements a minimal version:

  • The pictures are replaced with prozaic numbers
  • The number of cards is fixed to 20 and the layout is hard-coded
  • There is only one player
  • There is no score card

But most of these limitations are easy to fix - see the exercises.


 # memorygame.tcl --
 #    A basic implementation of the game of "Memory"
 #

 package require Tk

 #
 # Set up the buttons (they play the role of the picture cards)
 #
 set values [list]
 for { set i 1 } { $i <= 10 } { incr i } {
    lappend values $i $i
 }

 for { set i 1 } { $i <= 20 } { incr i } {
    set idx [expr {int(rand()*[llength $values])}]
    set label_text($i) [lindex $values $idx]
    set values [lreplace $values $idx $idx]

    button .b_$i -text " " -command [list showLabel $i] -width 3
 }

 button .next -text "Next" -command nextMove
 label  .empty -text " "

 grid   .b_1  .b_2  .b_3  .b_4  .b_5
 grid   .b_6  .b_7  .b_8  .b_9  .b_10
 grid   .b_11 .b_12 .b_13 .b_14 .b_15
 grid   .b_16 .b_17 .b_18 .b_19 .b_20
 grid   .empty  .next -     -     -

 #
 # Initialise
 #
 set click_count    0
 set clicked_values [list]

 #
 # Handle selections
 #
 proc showLabel {label} {
    global click_count
    global clicked_values
    global label_text

    if { $click_count >= 2 } { return }

    incr click_count
    .b_$label configure -text $label_text($label)

    lappend clicked_values $label

    if { $click_count == 2 } {
       set label1 [lindex $clicked_values 0]
       set label2 [lindex $clicked_values 1]
       if { $label_text($label1) == $label_text($label2) } {
          foreach label $clicked_values {
             .b_$label configure -state disabled
          }
          set clicked_values [list]
          set click_count    0
       }
    }
 }

 #
 # Handle next move
 #
 proc nextMove {} {
    global clicked_values
    global click_count

    foreach label $clicked_values {
       .b_$label configure -text " "
    }
    set clicked_values [list]
    set click_count 0
 }

Exercises for the young programmers for whom this is meant:

  • Use names instead of numbers
  • Can you adjust the game to, say, 15 pairs? 20 pairs? An arbitrary number? (the latter is a bit more difficult) What do you need to change in the code?
  • Can you come up with a strategy? What is the minimal number of steps?
  • Add a score card (showing the number of steps so far, and how pairs were found)
  • For the adventurous: add a second player
  • For the whizkids: turn this into a tic-tac-toe game

[ Category Education ]