Version 3 of 15-puzzle

Updated 2016-02-21 18:19:19 by HJG

if 0 {


Introduction

HJG 2016-02-16: There is a 15-puzzle in the Tk-demo. It uses buttons for the tiles and place to move the buttons around.

Other variants here on the wiki are The Classic 15 Puzzle and N-puzzle, but they are quite lengthy.
Both programs use numbers - it would be nice to have a variant that can use other symbols and/or a sliced-up picture.

Currently, there is a draft-task for the 15-puzzle at rosettacode , so to fill in an entry for tcl,
I wanted a fairly short and simple version of that puzzle.

Starting with the layout from A small calculator, I'm using a grid of buttons here,
and moving around the text on the buttons.
Also, there is only a limited number of canned puzzles (as in "1" :).

}


Code

 # 15puzzle_05.tcl - HaJo Gurt - 2016-02-16
 # http://wiki.tcl.tk/14403

 # 15-Puzzle - with grid, buttons and colors

  package require Tk

  set progVersion "15-Puzzle v0.15";        # 2016-02-17

  global msg Moves
  set msg " "
  set Moves 0

  set Keys { 11 12 13 14  21 22 23 24  31 32 33 34  41 42 43 44 }

  set Goa1 {  A  B  C  D   E  F  G  H   I  K  L  M   N  O  P  _ }; # Rows LTR   / 1:E : 108
  set Goa2 {  A  E  I  N   B  F  K  O   C  G  L  P   D  H  M  _ }; # Cols forw. / 1:M : 114
 #set Goa3 {  A  M  L  K   B  N  _  I   C  O  P  H   D  E  F  G }; # Spiral CCW / 0   : 121
 #set Goa4 {  A  B  C  D   M  N  O  E   L  _  P  F   K  I  H  G }; # Spiral CW1 / 0   : 154

  set Puz1 {  A  B  C  D   E  F  G  H   I  K  L  M   N  O  P  _ }; # solved
  set Puz2 {  C  A  F  B   E  G  P  N   D  L  H  I   O  K  M  _ }; # from Tk-demo

  set PuzT {  T  h  e  F   i  f  t  e   e  n  P  u   z  z  l  e }; # Title
  set GoaT {  x  x  x  F   i  f  t  e   e  n  x  x   x  x  x  x }; # title-highlight

  set Puzz $PuzT
  set Goal $GoaT

 #---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+---

  proc Move {k} { 
  # find key with the empty space:
    set e -1
    foreach p $::Keys  {
      set t [.key$p cget -text]
      if { $t eq "_" } { set e $p }
    }
    if {$e < 0} {return 0};    # no empty tile found 

    set t [.key$k cget -text]
    .key$e config -text $t  
 #-state active 
 #-state normal
 #-relief raised  
    .key$k  config -text "_";  # -background gray
    return 1
  }

  proc Check {} { 
    set ok 0
    set i  0
    foreach k $::Keys {
      set t [.key$k cget -text]

      set g [lindex $::Goal $i]
      incr i

      .key$k config -background white
      if { $t eq $g  } { .key$k config -background lightgreen; incr ok }
 #lime : only in Tcl/Tk 8.6

      if { $t eq "_" } { .key$k config -background gray }
 #-relief sunken   -state disabled 
    }
    update

    if { $ok > 15 && $::Moves > 0} {
      foreach k $::Keys  {
        .key$k flash; bell; 
      }
    }
  }

  proc Click {k} { 
    set  ::msg ""
    set val [.key$k cget -text]
    set ok [Move $k]

    incr ::Moves $ok
    wm title . "$::Moves moves"
    Check
  }

  proc New15 {P} {
    if { $P == 1} {
      set ::Puzz $::Puz1
      set ::Goal $::Goa1
    } else {
      set ::Puzz $::Puz2
      set ::Goal $::Goa1
    } 
    if { $P == 0} {
      set ::Puzz $::PuzT
      set ::Goal $::GoaT
    }
    set ::Moves 0

    set i 0 
    foreach k $::Keys  {
      set t [lindex $::Puzz $i]
      incr i
      .key$k config -text $t -background white;  # white
    }
    set ::msg "New game"
    wm title . $::msg
    Check
  }

 #button .quit   -text "Off"      -fg red  -command  exit
  button .newB   -text "Reset"    -fg blue -command {New15 1}
  button .newA   -text "New Game" -fg red  -command {New15 2}

  foreach k $::Keys {
    button .key$k -text "$k" -width 4 -command "Click $k"
  } 

  grid .newB x .newA -sticky nsew

  grid .key11 .key12 .key13 .key14  -sticky nsew  -padx 2 -pady 2
  grid .key21 .key22 .key23 .key24  -sticky nsew  -padx 2 -pady 2
  grid .key31 .key32 .key33 .key34  -sticky nsew  -padx 2 -pady 2
  grid .key41 .key42 .key43 .key44  -sticky nsew  -padx 2 -pady 2

  grid configure .newA  -columnspan 2 -padx 4
  grid configure .newB  -columnspan 2 -padx 4

  New15 0
  wm title . $progVersion
  focus -force .
 #wm resizable . 0 0

Comments

HJG The game is working, but there is no check yet if the clicked button is next to the empty tile.

I wanted to take care of that with '-state disabled' / '-state normal', but doing that resulted in some strange effects...

Also, the buttons for new game etc. are not final.


See also: