if 0 {[Richard Suchenwirth] 2004-11-14 - Domino is a popular game. In this weekend fun project, I wanted to have it in [Tcl]/[Tk] too. [http://mini.net/files/domino.gif] The real multiplayer game can't be implemented, as there's no way for one player to see a piece, while another doesn't - but at least one can use this for mathematical games with dominoes, as described in Martin Gardner's "Mathematical Circus". Drag a piece with left mouse button down, rotate it (counterclockwise 90 degrees) with right-click. } package require Tk namespace eval domino { variable bg black fg white size 30 #-- "Visual" definition of dot patterns - "sugared lists" variable pattern array set pattern { 0 {0 0 0 0 0 0 0} 1 {0 0 0 1 0 0 0} 2 {1 0 0 0 0 0 1} 3 {1 0 0 1 0 0 1} 4 {1 0 1 0 1 0 1} 5 {1 0 1 1 1 0 1} 6 {1 1 1 0 1 1 1} } variable points {1 1 1 2 1 3 2 2 3 1 3 2 3 3} } if 0 {This "constructor" creates a domino piece on the [canvas] ''w'', landscape oriented, with top left corner at ''x''/''y'' and the specified two point values (0..6). For allowing motion, all canvas items belonging to a piece with values p|q are tagged with * mv (so motion bindings have a common target) * d-$p$q for unique identification (assuming no duplicate pieces) The bd-$p$q tags aren't used yet - in future one might use them for reverting a piece, i.e. raising or lowering the rectangle. } proc domino::create {w x y val1 val2} { variable bg; variable fg; variable size set tags [list mv d-$val1$val2] set x1 [expr {$x+$size-0.5}] set y1 [expr {$y+$size}] $w create rect $x $y [expr {$x+2*$size}] $y1 \ -fill $bg -tags [linsert $tags 0 bd-$val1$val2] $w create line $x1 $y $x1 $y1 -fill $fg -tags $tags dots $w $x $y $val1 $tags dots $w [expr {$x+$size}] $y $val2 $tags } if 0 {Dots are drawn for a given value as ovals:} proc domino::dots {w x y val tags} { variable fg; variable size; variable points; variable pattern set d [expr {$size/4.}] foreach bit $pattern($val) {y0 x0} $points { if $bit { $w create oval [expr {$x+($x0-0.5)*$d}] [expr {$y+($y0-0.5)*$d}] \ [expr {$x+($x0+0.5)*$d}] [expr {$y+($y0+0.5)*$d}] -fill $fg \ -tags $tags } } } if 0 {Pieces are rotated around the center of their bounding box with the usual "convert to polar coordinates, adjust angle, convert back to Cartesian coordinates" algorithm. Due to rounding problems, sometimes the line in the middle of a piece comes slightly crooked:} proc domino::rotate w { foreach tag [$w gettags current] { if [regexp ^(d-.+) $tag -> this] break } foreach {x0 y0 x1 y1} [$w bbox $this] break set xm [expr {($x0+$x1)/2.}] set ym [expr {($y0+$y1)/2.}] set da [expr {acos(-1)/2.}] foreach item [$w find withtag $this] { set coords {} foreach {x y} [$w coords $item] { set r [expr {hypot($y-$ym, $x-$xm)}] set a [expr {abs($x-$xm)<1e-17? 0: atan2($y-$ym, $x-$xm)-$da}] set x [expr {$xm+$r*cos($a)}] set y [expr {$ym+$r*sin($a)}] lappend coords $x $y } $w coords $item $coords } } if 0 {Clicking on a piece records the click position, and its "catch-all" tag, in global variables:} proc mv'1 {w x y} { set ::_x $x; set ::_y $y foreach tag [$w gettags current] { if [regexp ^(d-.+) $tag -> ::_tag] break } } if 0 {Moving the mouse with button 1 down moves the items with the "catch-all" tag with the mouse pointer:} proc mv'motion {w x y} { $w raise $::_tag $w move $::_tag [expr {$x-$::_x}] [expr {$y-$::_y}] set ::_x $x; set ::_y $y } #-- The main routine makes a board and the classic 28 pieces: pack [canvas .c -bg darkgreen -width 500 -height 350] -fill both -expand 1 for {set left 0} {$left<=6} {incr left} { for {set right $left} {$right<=6} {incr right} { domino::create .c [expr $left*65+10] [expr $right*35+100] $left $right } } .c bind mv <1> {mv'1 %W %x %y} .c bind mv {mv'motion %W %x %y} .c bind mv <3> {domino::rotate %W} #-- Little development helpers (optional): bind . {exec wish $argv0 &; exit} bind . {console show} if 0 { [rdt] Boy, [RS] does good work. ---- [Category Games] | [Arts and crafts of Tcl-Tk programming] }