Skolem

 

ulis, 2005-06-25. Une récréation mathémathique à partir des suites de Skolem. Facile... et mathémathique.


Pourquoi

Pour faire partager le goût des mathématiques à travers un jeu.


Comment

Aucune difficulté ici : il s'agit de traîner des objets sur un canvas.


Le jeu

Bah... inutile de faire un dessin : c'est facile. Suffit de trouver le maximum de combinaisons.


Le script

  # ######################
  #
  # Skolem: main
  #
  # ######################

  # -----
  # packages
  # -----

  package require Tk

  # -----
  # global
  # -----

  array set {} \
  {
    user    user
    max     4
    x0      20
    y0      20
    xunit   25
    yunit   10
    radius  8
    font1   {Arial 12 bold}
    font2   {Arial 10 bold}
    date    %Y-%m-%d
    scores  {}
  }

  # -----
  # main
  # -----

  source Skolem.files.tcl
  source Skolem.GUI.tcl
  source Skolem.moves.tcl

Skolem.files.tcl

  # ######################
  #
  # Skolem: files
  #
  # ######################

  set (fn:config) Skolem.config
  set (fn:score) Skolem.score

  # read
  proc readFile {fn} \
  {
    set lines [list]
    catch \
    {
      set fp [open $fn r]
      set file [split [read $fp] \n]
      close $fp
    }
    foreach line $file \
    {
      lappend lines [split $line \t]
    }
    return $lines
  }

  # source
  proc sourceFile {fn} \
  {
    catch { source $fn }
  }

  # write
  proc writeFile {fn lines} \
  {
    catch \
    {
      set fp [open $fn w]
      foreach line $lines \
      {
        lappend file [join $line \t]
      }
      puts -nonewline $fp [join $file \n]
      close $fp
    } msg
    if {$msg != ""} { tk_messageBox -message $msg }
  }

  # save files
  proc saveFiles {} \
  {
    variable {}
    # config
    lappend conf [list "global {}"]
    lappend conf [list "array set {} {"]
    lappend conf [list user "{$(user)}"]
    lappend conf [list max $(max)]
    lappend conf [list x0 $(x0)]
    lappend conf [list y0 $(y0)]
    lappend conf [list xunit $(xunit)]
    lappend conf [list yunit $(yunit)]
    lappend conf [list radius $(radius)]
    lappend conf [list font1 "{$(font1)}"]
    lappend conf [list font2 "{$(font2)}"]
    lappend conf [list "}"]
    writeFile $(fn:config) $conf
    # score
    lappend scor [list "global {}"]
    foreach score $(scores) \
    { lappend scor [list lappend (scores) \[list $score \]] }
    writeFile $(fn:score) $scor
  }

  # read config
  sourceFile $(fn:config)
  # read score
  sourceFile $(fn:score)

Skolem.GUI.tcl

  # ######################
  #
  # Skolem: GUI
  #
  # ######################

  source Skolem.mouse.tcl
  source Skolem.legs.tcl
  set (curmax) $(max)

  # create GUI
  proc createGUI {} \
  {
    variable {}
    # title
    wm title . "Skolem $(max)"
    # main parts
    catch { destroy .c .f }
    frame .f
    canvas .c -bg gray75
    # frame
    set (xmax) [expr {$(max) * $(xunit)}]
    set (curmax) $(max)
    button .f.z -width 10 -bd 1 -text Z -command createGUI
    scale .f.s -orient horizontal -from 1 -to 8 \
      -variable (curmax) -command change \
      -width 15 -sliderlength 15 -bd 1 \
      -length 100 -bigincrement 1 -showval 0
    entry .f.e -width 15 -textvariable (user) \
      -bd 1 -justify center
    set (curcount) 0
    foreach score $(scores) \
    {
      if {[lindex $score 0] == $(max)} { incr (curcount) }
    }
    button .f.b -width 10 -bd 1 -textvar (curcount) \
      -command displayScore
    # canvas
    set y $(y0)
    for {set num 0} {$num <= $(max)} {incr num} \
    {
      set height [createLegs $num $y]
      incr y [expr {$height + 2 * $(yunit)}]
    }
    set (height) $y
    set x0 [expr {$(xmax) * 2}]
    .c create rectangle 0 0 $x0 $(height) \
      -fill gray80 -outline gray80 -tags r
    .c lower r
    incr x0 $(xunit)
    set y0 [expr {$(height) / 2}]
    set y1 [expr {$y0 - $(radius)}]
    set y2 [expr {$y0 + $(radius)}]
    for {set i 0} {$i < 2 * $(max) + 1} {incr i} \
    {
      set x1 [expr {$x0 - $(radius)}]
      set x2 [expr {$x0 + $(radius)}]
      .c create oval $x1 $y1 $x2 $y2 \
        -fill red -outline red -tags tt$i
      .c lower tt$i
      set (tt$i) ""
      incr x0 $(xunit)
    }
    .c config -width $x0 -height $(height)
    # place & display
    grid .f -sticky w
    grid .f.z .f.s .f.e .f.b -padx 10 -pady 10
    grid .c
    # events
    bind .c <ButtonPress> {press %x %y}
    bind .c <ButtonRelease> {release %x %y}
    bind .c <Motion> {motion %x %y}
    wm protocol . WM_DELETE_WINDOW { saveFiles; exit }
  }

  # change max
  proc change {max} \
  {
    variable {}
    if {$(max) == $max} { return }
    set (max) [expr {int($max)}]
    createGUI
  }

  # display current score
  proc displayScore {} \
  {
    variable {}
    set scor [list]
    foreach score $(scores) \
    {
      if {[lindex $score 0] == $(max)} \
      { lappend scor [lrange $score 1 end] }
    }
    tk_messageBox -message [join $scor \n]
  }

Skolem.legs.tcl

  # ######################
  #
  # Skolem: legs & feet
  #
  # ######################

  # create a leg
  proc createLegs {num y} \
  {
    variable {}
    # compute characteristics
    set height [expr {5 + ($num + 1) * $(yunit)}]
    set width [expr {$num * $(xunit)}]
    set w2 [expr {$width / 2}]
    set x [expr {$(xmax) - $w2}]
    # create 1st leg
    .c create line 0 0 0 $height \
      -width 3 -tags t$num
    # create 1st foot
    createFoot $num a 0 $height
    # create 2nd leg & 2nd foot
    .c create line 0 0 $width 0 \
      -width 3 -tags t$num
    .c create line $width 0 $width $height \
      -width 3 -tags t$num
    createFoot $num b $width $height
    # move to the right place
    move $num $x $y
    # save place
    set (h$num) [.c coords oa$num]
    # return height
    return $height
  }

  # create a foot
  proc createFoot {num snum x y} \
  {
    variable {}
    # compute outline
    set x1 [expr {$x - $(radius)}]
    set x2 [expr {$x + $(radius)}]
    set y1 [expr {$y - $(radius)}]
    set y2 [expr {$y + $(radius)}]
    # create circle
    set tags [list t$num o$snum$num]
    .c create oval $x1 $y1  $x2 $y2 \
      -fill red -outline red -tags $tags
    # put num
    set tags [list t$num t$snum$num]
    .c create text $x $y -text $num \
      -fill gray75 -tags $tags
    # create ghost
    .c create oval $x1 $y1  $x2 $y2 \
      -fill gray75 -outline gray75 -tags g$snum$num
    .c create text $x $y -text $num \
      -fill gray90 -tags g$snum$num
    .c lower g$snum$num
  }

  # move legs
  proc move {num dx dy} \
  {
    variable {}
    .c move t$num $dx $dy
    .c move ga$num $dx $dy
    .c move gb$num $dx $dy
  }

Skolem.mouse.tcl

  # ######################
  #
  # Skolem: mouse
  #
  # ######################

  # mouse button was pressed
  proc press {x y} \
  {
    variable {}
    # find closest
    set index [.c find closest $x $y $(radius)]
    set tag [lindex [.c gettags $index] 0]
    set num [string range $tag 1 end]
    if {[string is integer -strict $num]} \
    {
      #found! give som feedback
      .c itemconfig ta$num -fill white
      .c itemconfig tb$num -fill white
      # set current moved num
      set (num) $num
      # save current coords
      set (last) [list $x $y]
      # unregister from slots
      for {set i 0} {$i < 2 * $(max) + 1} {incr i} \
      { if {$(tt$i) == $num} { set (tt$i) "" } }
    }
  }

  # mouse button was released
  proc release {x y} \
  {
    variable {}
    # was a num moving?
    if {[info exists (num)]} \
    {
      # end of move, give some feedback
      .c itemconfig ta$(num) -fill gray75
      .c itemconfig tb$(num) -fill gray75
      # get slots
      set hits [hits $(num)]
      foreach {a b} $hits break
      set ok [expr {[llength $hits] == 2}]
      if {$ok} \
      {
        # are the 2 slots free?
        set ok [expr {($(tt$a) == "") && ($(tt$b) == "")}]
      }
      if {$ok} \
      {
        # register for each slot
        set (tt$a) $(num)
        set (tt$b) $(num)
        # center the feet
        goto $(num) [.c coords tt$a]
        # check if done
        check
      } \
      else \
      {
        # go back home
        goto $(num) $(h$(num))
      }
      unset (num)
    }
  }

  # mouse was moving
  proc motion {x y} \
  {
    variable {}
    if {[info exists (num)]} \
    {
      foreach {x0 y0} $(last) break
      set dx [expr {$x - $x0}]
      set dy [expr {$y - $y0}]
      .c move t$(num) $dx $dy
      set (last) [list $x $y]
    }
  }

Skolem.moves.tcl

  # ######################
  #
  # Skolem: moves
  #
  # ######################

  # go to home
  proc goto {num coords} \
  {
    variable {}
    foreach {x y} $coords break
    foreach {xa ya} [.c coords oa$num] break
    set dx [expr {$x - $xa}]
    set dy [expr {$y - $ya}]
    .c move t$num $dx $dy
  }

  # compute all hits
  proc hits {num} \
  {
    variable {}
    # init res, a & b coords
    set res [list]
    foreach {xa ya} [.c coords ta$num] break
    foreach {xb yb} [.c coords tb$num] break
    # check each slot
    set x0 [expr {$(xmax) * 2 + $(xunit)}]
    set y0 [expr {$(height) / 2}]
    for {set i 0} {$i < 2 * $(max) + 1} {incr i} \
    {
      # a met?
      if {[expr {abs($xa - $x0) + abs($ya - $y0) <= 2 * $(radius)}]} \
      { lappend res $i }
      # b met?
      if {[expr {abs($xb - $x0) + abs($yb - $y0) <= 2 * $(radius)}]} \
      { lappend res $i }
      incr x0 $(xunit)
    }
    # res
    return $res
  }

  # check result
  proc check {} \
  {
    variable {}
    # count placed feet
    set count 0
    set max [expr {2 * $(max) + 1}]
    for {set i 0} {$i < $max} {incr i} \
    { if {$(tt$i) != ""} { incr count; append feet "$(tt$i)." } }
    if {$count == $max} \
    {
      # done
      set score ""
      foreach score $(scores) \
      {
        foreach {level skolem name date} $score break
        if {$level == $(max) && $skolem == $feet} \
        {
          tk_messageBox -message "$name $date"
          set score "found"
          break
        }
      }
      if {$score != "found"} \
      {
        set date [clock format [clock seconds] -format $(date)]
        lappend (scores) [list $(max) $feet $(user) $date]
        incr (curcount)
      }
    }
  }

  createGUI

Voir aussi


Discussion


Catégorie Jeu | Catégorie Mathématiques | Catégorie Exemple