Licht aus!

Licht aus, bitte!

Ziel des Spiels ist Schlafenszeit: alle Lichter aus. Ein Klick schaltet sowohl das geklickte Feld als auch die Nachbarfelder um. Etwas knifflig.


#!/usr/bin/wish

package require Tk

if {[catch {lassign "$argv 3" rows}]} then {
  set rows 4
}

set tileSize 80

package require Tk
bind [winfo class .] <Destroy> exit
wm resizable . no no
wm title . "Licht aus, bitte!"

pack [canvas .c]

namespace path ::tcl::mathop

.c configure -width [* $rows $tileSize] -height [* $rows $tileSize]

proc toggleOneField {c r {canvas .c}} {
  variable rows
  if {$c >= 0 && $c < $rows && $r >= 0 && $r < $rows} then {
    set id [$canvas find withtag c$c&&r$r]
    if {"on" in [$canvas gettags $id]} then {
      .c dtag $id on
      .c itemconfigure $id -fill [$canvas cget -bg]
    } else {
      .c addtag on withtag $id
      .c itemconfigure $id -fill white
    }
  }
}

proc toggleField {c r {canvas .c}} {
  toggleOneField $c $r $canvas
  toggleOneField [+ $c 1] $r $canvas
  toggleOneField [- $c 1] $r $canvas
  toggleOneField $c [+ $r 1] $canvas
  toggleOneField $c [- $r 1] $canvas
  if {[$canvas find withtag on] eq ""} then {
    # wm title . "Danke schön, gute Nacht!"
    .c delete all
    .c create text\
      [/ [.c cget -width] 2]\
      [/ [.c cget -height] 2]\
      -font "Times 24 bold italic"\
      -justify center\
      -text "Danke\nschön!\nGute\nNacht!"\
      -tags Danke
    blink .c\
      -red0 0     -green0 0     -blue0 65535\
      -red1 65535 -green1 65535 -blue1 0
  }
}

proc blink {widget args} {
  set pi [expr {atan2(0,-1)}]
  set item {-att -fg
            -step 0
            -red0 0
            -green0 0
            -blue0 0
            -red1 65535
            -interval 25
            -green1 65535
            -blue1 65535
            -action continue}
  dict for {key val} $args {
    dict set item $key $val
  }
  if {[dict get $item -action] eq "continue"} then {
    dict incr item -step
    if {[dict get $item -step] >= 100} then {
      dict set item -step 0
    }
    set factor [expr {
      (cos($pi*2*[dict get $item -step]/100)+1)/2
    }]
    set red0 [dict get $item -red0]
    set red1 [dict get $item -red1]
    set red [expr {$red0+int(($red1-$red0)*$factor)}]
    set green0 [dict get $item -green0]
    set green1 [dict get $item -green1]
    set green [expr {$green0+int(($green1-$green0)*$factor)}]
    set blue0 [dict get $item -blue0]
    set blue1 [dict get $item -blue1]
    set blue [expr {$blue0+int(($blue1-$blue0)*$factor)}]
    set r [format %04x $red]
    set g [format %04x $green]
    set b [format %04x $blue]
    $widget itemconfigure Danke -fill #$r$g$b
    after [dict get $item -interval]\
      [list blink $widget {*}$item]
  } else {
    foreach event [after info] {
      if {[lindex [after info $event] 0 0] eq "blink"} then {
        after cancel $event
      }
    }
  }
}



proc takeNfromList {n list} {
  if {$n > 0} then {
    set rand [expr {int(rand()*[llength $list])}]
    list [lindex $list $rand] {*}[takeNfromList [- $n 1] [lreplace $list $rand $rand]]
  }
}

proc randomNumOfFields rows {
  expr {$rows+int(rand()*$rows*($rows-2))}
}

apply {
  {canvas rows tileSize} {
    $canvas delete all
    for {set c 0} {$c < $rows} {incr c} {
      for {set r 0} {$r < $rows} {incr r} {
        $canvas create rectangle\
          [+ [* $c $tileSize] 1]\
          [+ [* $r $tileSize] 1]\
          [+ [* $c $tileSize] $tileSize -1]\
          [+ [* $r $tileSize] $tileSize -1]\
          -width 0 -fill white -tags "c$c r$r on"
        $canvas bind c$c&&r$r <1> "toggleField $c $r"
        lappend fields "$c $r"
      }
    }
    foreach field\
      [takeNfromList [randomNumOfFields $rows] $fields] {
      toggleField {*}$field $canvas
    }
  }
} .c $rows $tileSize

11.3.2022