Bonjour,

Le fait de placer un shell dans /usr/local/bin ne suffit pas toujours �
ce qu'il puisse �tre lanc� d'un clic de souris sur Kfm ou Disk
Navigator.

Je n'ai pas trouv� de solution avec le programme ci-joint (que je lance
correctement en console par ./tkataxx.tcl2).

Je vous le laisse ci-joint pour que vous ayez toutes les infos
permettant de comprendre (� signaler que je n'ai pas eu ce probl�me avec
un autre programme en Tcl Tk).

Cordialement.

-- 
Alain Beyrand
#!/bin/bash
# the next line restarts using wish \
exec wish "$0" "$@"

#################################################################
#
# TkAtaxx
#
# by Keith P. Vetter  ([EMAIL PROTECTED])
# Copyright (c) 1995 Keith P. Vetter
#
# TkAtaxx is tcl/tk implementation of the Ataxx arcade game. It is
# written solely in tcl/tk. The computer uses a multi-level game tree
# search routine with alpha-beta pruning.
#
# Revision history:
# Keith Vetter  1/6/95  - Initial revision
# Keith Vetter  5/16/95 - Added help and cleaned up code
# Keith Vetter  8/22/95 - Ported to tk 4.0
# Keith Vetter  1/25/96 - Minor cleanup, found but didn't fix resize bug
#       - fixed bug when player has no moves deep in the search tree.
#
if {[info tclversion] < 7.0 || $tk_version < 3.3} {
   puts stdout ""
   puts stdout "You need TCL version 7.0 and TK version 3.3 for this program."
   puts stdout ""
   exit
}
puts ""
puts "TkAtaxx 1.05      by Keith Vetter"
puts ""

# To Do
#  go/stop button when both are computers
#  multi-level hint
#  remove recursion in do_move/robot
#  check turn in mousing, change cursor
#
##+#########################################################################
## 
## Init
## 
## Sets up some global variables
## 
proc init {{cs 50}} {
    global state newb

    set state(cs) $cs                           ;# Size of a cell
    set state(bs) [expr round($cs * .9)]        ;# Size of a blob
    set state(brd) -1                           ;# Last board used
    set state(c,1) Red                          ;# Colors for each player
    set state(c,2) Green
    set state(1) 0                              ;# Human
    set state(2) 1                              ;# Computer
    set state(skill) Greedy                     ;# Skill level
    set state(Verbose) 1                        ;# Verbosity on
    set state(conf) 0                           ;# Configuring size flag
;#
;# Various boards to play on
;#
    set newb(0) {{2 0} {4 0} {2 1} {4 1} {0 2} {6 2} {0 3} \
            {3 3} {6 3} {0 4} {6 4} {2 5} {4 5} {2 6} {4 6}}
    set newb(1) {{3 0} {3 1} {3 2} {0 3} {1 3} {2 3} \
            {4 3} {5 3} {6 3} {3 4} {3 5} {3 6}}
    set newb(2) {{3 0} {1 2} {2 2} {4 2} {5 2} {0 3} {1 3} \
            {5 3} {6 3} {1 4} {2 4} {4 4} {5 4} {3 6}}
    set newb(3) {{1 0} {5 0} {0 1} {6 1} {3 3} {0 5} {6 5} {1 6} {5 6}}
    set newb(4) {{2 0} {4 0} {2 1} {4 1} {0 3} {6 3} {2 5} {4 5} {2 6} {4 6}}
    set newb(5) {{3 0} {3 1} {0 3} {1 3} {5 3} {6 3} {3 5} {3 6}}
    set newb(6) {{3 1} {2 2} {4 2} {1 3} {5 3} {2 4} {4 4} {3 5}}
    set newb(7) {{2 0} {4 0} {0 2} {6 2} {0 4} {6 4} {2 6} {4 6}}
    set newb(8) {{3 0} {2 1} {4 1} {1 2} {5 2} {0 3} {6 3} {1 4} \
            {5 4} {2 5} {4 5} {3 6}}
    set newb(9) {{2 1} {4 1} {1 2} {5 2} {1 4} {5 4} {2 5} {4 5}}
    set newb(10) {{2 0} {4 0} {2 2} {4 2} {1 3} {5 3} {2 4} {4 4} {2 6} {4 6}}
    set newb(11) {{3 1} {3 2} {1 3} {2 3} {3 3} {4 3} {5 3} {3 4} {3 5}}
    set newb(12) {{1 1} {2 1} {3 1} {4 1} {5 1} {1 2} \
            {5 2} {1 3} {5 3} {1 4} {5 4} {1 5} {2 5} {3 5} {4 5} {5 5}}
    set newb(13) {{2 1} {3 1} {4 1} {1 2} {5 2} {1 3} \
            {5 3} {1 4} {5 4} {2 5} {3 5} {4 5}}
    set newb(14) {{2 1} {4 1} {1 2} {2 2} {4 2} {5 2} \
            {1 4} {2 4} {4 4} {5 4} {2 5} {4 5}}
    set newb(15) {{1 1} {5 5} {1 5} {5 1}}
    set newb(16) {{1 1} {2 1} {4 1} {5 1} {1 2} {5 2} \
            {1 4} {5 4} {1 5} {2 5} {4 5} {5 5}}
    set newb(17) {{3 2} {2 3} {3 3} {4 3} {3 4}}
    set newb(18) {{3 2} {2 3} {4 3} {3 4}}
    set newb(19) {{3 1} {3 2} {1 3} {2 3} {4 3} {5 3} {3 4} {3 5}}
    set newb(20) {{2 0} {3 0} {4 0} {3 1} {0 2} {6 2} \
            {0 3} {1 3} {5 3} {6 3} {0 4} {6 4} {3 5} {2 6} {3 6} {4 6}}
    set newb(21) {{2 0} {4 0} {3 1} {0 2} {6 2} {1 3} \
            {5 3} {0 4} {6 4} {3 5} {2 6} {4 6}}
    set newb(22) {{3 1} {1 3} {3 3} {5 3} {3 5}}
    set newb(23) {{1 1} {3 1} {5 1} {1 3} {3 3} {5 3} {1 5} {3 5} {5 5}}
    set newb(24) {}
    set newb(25) {{2 2} {4 2} {3 3} {2 4} {4 4}}
    set newb(26) {{1 1} {5 1} {2 2} {4 2} {3 3} {2 4} {4 4} {1 5} {5 5}}
    set newb(27) {{2 0} {3 0} {4 0} {2 1} {4 1} {0 3} \
            {6 3} {2 5} {4 5} {2 6} {3 6} {4 6}}
    set newb(28) {{1 0} {3 0} {5 0} {0 1} {2 1} {4 1} {6 1} \
            {1 2} {3 2} {5 2} {0 3} {2 3} {4 3} {6 3} {1 4} \
            {3 4} {5 4} {0 5} {2 5} {4 5} {6 5} {1 6} {3 6} {5 6}}
    set newb(29) {{1 1} {5 1} {2 2} {4 2} {2 4} {4 4} {1 5} {5 5}}
    set newb(30) {{3 0} {2 1} {4 1} {0 3} {6 3} {2 5} {4 5} {3 6}}
    set newb(31) {{3 0} {0 3} {6 3} {3 6}}
    set newb(32) {{3 1} {1 3} {5 3} {3 5}}
    set newb(33) {{2 0} {3 0} {4 0} {0 2} {1 2} {3 2} {5 2} \
            {6 2} {0 3} {6 3} {0 4} {1 4} {3 4} {5 4} {6 4} {2 6} {3 6} {4 6}}
    set newb(34) {{2 1} {4 1} {0 2} {1 2} {3 2} {5 2} {6 2} \
            {3 3} {0 4} {1 4} {3 4} {5 4} {6 4} {2 5} {4 5}}
    set state(b) 35                             ;# Number of boards
}
##+#########################################################################
## 
## Display
## 
## Sets up the display
## 
proc display {} {
    global state

    wm title . "TkAtaxx"
    frame .m                                    ;# Frame for the menus
    frame .ftop -bd 2 -relief ridge
    frame .fbot
    pack .m .ftop .fbot -side top -fill both
    draw_menus                                  ;# Draw the menus 
    draw_board                                  ;# Draw the actual board

    label .msg -relief ridge -textvariable state(msg) -anchor w
    pack .msg -side top -fill x -in .fbot

    frame .fsc -bd 2 -relief ridge
    frame .fred
    frame .fgreen
    pack .fsc -side left -ipadx 5 -expand yes -fill y -in .fbot
    pack .fred .fgreen -side top -in .fsc
    
    canvas .c_p1 -width 16 -height 16           ;# Status area
    .c_p1 create oval 2 2 15 15 -fill $state(c,1)
    canvas .c_p2 -width 16 -height 16
    .c_p2 create oval 2 2 15 15 -fill $state(c,2)
    label .p1 -text "Score: "
    label .p2 -text "Score: "
    label .p1_sc -textvariable state(sc,1) -width 2
    label .p2_sc -textvariable state(sc,2) -width 2
    pack .c_p1 .p1 .p1_sc -side left -in .fred
    pack .c_p2 .p2 .p2_sc -side left -in .fgreen

    scale .level -o h -from 0 -to 3 -relief ridge -command level -showv 0
    .level set 1
    pack .level -side right -expand yes -in .fbot -fill y

    bind .level <3> xx
    bind .level <2> {hint -1 ; break}
    bind .level <Shift-2> {hint -2 ; break}
}
##+#########################################################################
## 
## Level
## 
## Handles changes in the scale for the depth of search
## 
proc level {v} {
    global state
    
    set l(0) Random ; set l(1) Greedy
    set l(2) Brainy ; set l(3) Genius
    
    .level config -label "Skill: $l($v)"        ;# Change the label on scale
    set state(skill) $l($v)                     ;# Update menu
}
##+#########################################################################
## 
## Draw_board
## 
## Draws the playing field
## 
proc draw_board {{cs -1}} {
    global state

    if {$cs != -1} {
        set state(cs) $cs                       ;# Resize board
        set state(bs) [expr round($cs * .9)]    ;# Size of a blob
    }
    set wi [expr $state(cs) * 7]                ;# Total width

    catch {destroy .c}          ;# Delete old canvas
    canvas .c -width $wi -height $wi
    pack .c -in .ftop
    set state(Grid) 1
    grid
    
    bind .c <1> {mouse_down %x %y}
    return
}
##+#########################################################################
## 
## Redraw_board
## 
## Redraws all the pips and obstacles on the board
## 
proc redraw_board {{brd ""}} {
    global state bb

    if {$brd != ""} {set bb $brd}               ;# New board to use
    
    .c delete blob                              ;# Delete any existing stuff
    set state(sc,0) 0                           ;# Reset the scores
    set state(sc,1) 0                           ;# 0 is blanks, 1 is player 1
    set state(sc,2) 0                           ;# 2 is player 2
    set state(sc,3) 0                           ;# 3 is barriers
    
    for {set r 0} {$r < 7} {incr r} {           ;# Each row and column
        for {set c 0} {$c < 7} {incr c} {
            set cell [lindex $bb [index $r $c]] ;# What's in the cell
            incr state(sc,$cell)                ;# Update score info
            
            if {$cell == 3} {                   ;# Obstacle
                make_obstacle $r $c
            } elseif {$cell > 0} {              ;# Red or green pip
                make_blob $cell $r $c
            }
        }
    }
    set bb [lreplace $bb 121 end $state(sc,0) $state(sc,1) $state(sc,2) \
            $state(sc,3)]
}
##+#########################################################################
## 
## Resize
## 
## Called when the size or position of the window changes.
## 
proc resize {w h} {
    global state

puts "BROKEN" return
    
    if $state(conf) return                      ;# Already resizing

    set state(conf) 1                           ;# Set busy flag

    set hh [expr [winfo reqheight .m] + [winfo reqheight .fbot]]
    set sz [expr $h - $hh]                      ;# Assume this is minimum
    if {$w < $sz} {set sz $w}
    set cs [expr $sz / 7]                       ;# New cell size
    set sz [expr 5 + 7 * $cs]                   ;# New total size

    if {$cs != $state(cs)} {
        resize_board $cs                        ;# Resize the board
        wm geom . ${sz}x[expr $sz + $hh]        ;# Resize the window
    }
    set state(conf) 0                           ;# Clear busy flag
}
##+#########################################################################
## 
## Resize_board
## 
## Resizes the board with cell size CS
## 
proc resize_board {cs} {
    global state

    draw_board $cs                              ;# The basic board
    redraw_board                                ;# Add all the pips
}
    
##+#########################################################################
## 
## Grid
## 
## Toggles the display of a grid on the board
## 
proc grid {} {
    global state

    if {! $state(Grid)} {                       ;# Grid already exists
        .c delete grid
        return
    }
    
    set wi [expr $state(cs) * 7]                ;# Total width
    .c create rect 0 0 $wi $wi -width 5 -fill {} -tag grid
    
    for {set i 1} {$i < 7} {incr i} {           ;# Cell dividers
        set xy [expr $i * $state(cs)]
        .c create line 0 $xy $wi $xy -tag grid
        .c create line $xy $wi $xy 0 -tag grid
    }
}
##+#########################################################################
## 
## C_bbox
## 
## Returns the bounding box for a given row, col cell
## 
proc c_bbox {r c} {
    global state

    set bs2 [expr $state(bs) / 2.0]             ;# Half blob size
    set x [expr round(($c+.5) * $state(cs) - $bs2)];# Center less half blob
    set y [expr round(($r+.5) * $state(cs) - $bs2)]
    set x2 [expr $x + $state(bs)]
    set y2 [expr $y + $state(bs)]

    return [list $x $y $x2 $y2]
}
##+#########################################################################
## 
## Make_blob
## 
## Creates a new blob at location Row Col for WHO
## 
proc make_blob {who r {c -1}} {
    global state bb

    if {$c == -1} {                             ;# R,C is in index format
        set c [expr ($r % 11) - 2]
        set r [expr ($r / 11) - 2]
    }

    set col $state(c,$who)                      ;# Color to use
    set xy [c_bbox $r $c]
    eval .c create oval $xy -fill ${col}3 -tag \"blob blob${r}${c}\"
    eval .c create arc $xy -start 45 -extent 180 -fill ${col}1 -outline \"\" \
            -tag \"blob blob${r}${c}\"
    eval .c create oval [eval shrink $xy 5] -fill ${col}2 -outline \"\" \
            -tag \"blob blob${r}${c}\"
    
    set p [index $r $c]                         ;# Update board info
    set bb [lreplace $bb $p $p $who]            ;# Put new piece there
}
##+#########################################################################
## 
## Shrink
## 
## Shrinks rectangle specified by x,y x2,y2
## 
proc shrink {x y x2 y2 n} {
    set x [expr $x + $n]
    set y [expr $y + $n]
    set x2 [expr $x2 - $n]
    set y2 [expr $y2 - $n]

    return [list $x $y $x2 $y2]
}
##+#########################################################################
## 
## Grow_blob
## 
## Grows a blob at R,C
## 
proc grow_blob {who r c} {
    global state

    set xy [c_bbox $r $c]
    for {set i [expr $state(bs) / 2]} {$i >= 0} {incr i -1} {
        set bbox [eval shrink $xy $i]           ;# Bounding box of oval
        eval .c create oval $bbox -tag grow -fill $state(c,$who)
        update idletasks
    }
    make_blob $who $r $c
    .c delete grow
}
##+#########################################################################
## 
## Highlight
## 
## Highlights cell R, C
## 
proc highlight {r c} {
    
    if {$r == -1} {                             ;# -1 means delete highlight
        .c delete high
        return
    }
    eval .c create rect [c_bbox $r $c] -fill \"\" -tag \"blob high\" -width 5
    .c lower high
}
##+#########################################################################
## 
## Delete_blob
## 
## Deletes the blob from cell Row Col
## 
proc delete_blob {r {c -1}} {
    global bb

    if {$c == -1} {                             ;# R,C is in index format
        set c [expr ($r % 11) - 2]
        set r [expr ($r / 11) - 2]
    }
    .c delete blob${r}${c}

    set p [index $r $c]                         ;# Update board info
    set bb [lreplace $bb $p $p 0]               ;# Cell now empty
}
##+#########################################################################
## 
## Make_obstacle
## 
## Creates an obstacle in cell Row Col
## 
proc make_obstacle {r c} {
    global bb state

    set xy [c_bbox $r $c]                       ;# Where to put it
    set x  [lindex $xy 0]
    set y  [lindex $xy 1]
    set x2 [lindex $xy 2]
    set y2 [lindex $xy 3]

    .c create poly $x $y $x $y2 $x2 $y -fill white -tag blob
    .c create poly $x2 $y2 $x $y2 $x2 $y -fill gray45 -tag blob
    eval .c create rect [eval shrink $xy 2] -fill gray -outline \"\" -tag blob

    set xy [eval shrink $xy [expr $state(cs) / 5]]
    eval .c create rect $xy -fill $state(c,1) -out \"\" -tag \"blob center\"
}
##+#########################################################################
## 
## Clean_board
## 
## Deletes everything off the board
## 
proc clean_board {} {
    global bb
    
    .c delete blob                              ;# Delete the blobs
    
    set bb "4 4 4 4 4 4 4 4 4 4 4"              ;# BB is the board info
    set bb "$bb 4 4 4 4 4 4 4 4 4 4 4"          ;# ...w/ 2 row/col of sentinels
    
    set bb "$bb 4 4 0 0 0 0 0 0 0 4 4"          ;# Actual board part
    set bb "$bb 4 4 0 0 0 0 0 0 0 4 4"
    set bb "$bb 4 4 0 0 0 0 0 0 0 4 4"
    set bb "$bb 4 4 0 0 0 0 0 0 0 4 4"
    set bb "$bb 4 4 0 0 0 0 0 0 0 4 4"
    set bb "$bb 4 4 0 0 0 0 0 0 0 4 4"
    set bb "$bb 4 4 0 0 0 0 0 0 0 4 4"

    set bb "$bb 4 4 4 4 4 4 4 4 4 4 4"          ;# Bottom row sentinels
    set bb "$bb 4 4 4 4 4 4 4 4 4 4 4"
    set bb "$bb 45 2 2"
}
##+#########################################################################
## 
## Fill_board
## 
## Fills all blanks board positions with a blob. Called when the game
## is over.
## 
proc fill_board {who} {
    global state bb

    for {set r 0} {$r < 7} {incr r} {           ;# Search each row, column
        for {set c 0} {$c < 7} {incr c} {
            set p [index $r $c]
            if {[lindex $bb $p] == 0} {         ;# Is cell empty?
                make_blob $who $r $c            ;# Yep, create a blob here
                incr state(sc,$who)             ;# Increase score
                update idletasks                ;# More visually plesing
            }
        }
    }
        
}
##+#########################################################################
## 
## New_board
## 
## Creates a new board with obstacles of type N
## 
proc new_board {{n -1}} {
    global newb state bb mm                     ;# The boards

    if {$n == -1} {                             ;# Get random board to use
        set n [rand $state(b)]                  ;# Pick on at random
        if {$n == $state(brd)} {                ;# Same as last time
            set n [rand $state(b)]              ;# Pick another
        }
    }
    set state(brd) $n                           ;# Remember for next time

    clean_board                                 ;# Get rid of old stuff
    catch {unset mm}                            ;# Undo info
    
    set xy [index 0 0] ; set bb [lreplace $bb $xy $xy 1]
    set xy [index 6 6] ; set bb [lreplace $bb $xy $xy 1]
    set xy [index 6 0] ; set bb [lreplace $bb $xy $xy 2]
    set xy [index 0 6] ; set bb [lreplace $bb $xy $xy 2]
    foreach p $newb($n) {                       ;# Add the obstacles
        set xy [eval index $p]
        set bb [lreplace $bb $xy $xy 3]
    }
    redraw_board
    set state(init) $bb                         ;# Save initial position
    
    set state(turn)  1                          ;# Who's turn
    set state(state) 0                          ;# Where in the turn
    set state(n)     0                          ;# Which move
    set state(msg)   ""                         ;# Erase message area
    
    set state(tc) 0                             ;# VEB stats
    set state(c) 0                              ;# VEB stats
    
    return
}
##+#########################################################################
## 
## Rand [base]
## 
## per Knuth 3.6:
## 65277 mod 8 = 5 (since 65536 is a power of 2)
## c/m = .5-(1/6)\sqrt{3}
## c = 0.21132*m = 13849, and should be odd.
##
## If BASE is specified, then we return < BASE
##
proc rand {{base ""}} {
    global rseed

    if {! [info exist rseed]} {                 ;# Are we seeded?
        set x [lindex [time {file atime [exec tty]}] 0]
        set rseed [expr ($x + [file atime [exec tty]]) % 65536]
    }
    set rseed [expr (65277*$rseed+13849)%65536];# New value
    set rseed [expr ($rseed+65536)%65536]

    set value $rseed
    if {$base != ""} {                          ;# Return in a range
        set value [expr ($value * $base)/65536]
    }

    return $value
}


;# proc rand {args} {
;#   global rseed
;#
;#   set max 259200
;#   set argcnt [llength $args]
;#   if { $argcnt < 1 || $argcnt > 2 } {
;#     error "wrong # args: random limit | seed ?seedval?"
;#   }
;#   if ![string compare [lindex $args 0] seed] {
;#     if { $argcnt == 2 } {
;#       set rseed [lindex $args 1]
;#     } else {
;#       set rseed [expr ([pid]+[file atime /dev/kmem])%$max]
;#     }
;#     return
;#   }
;#   if ![info exists rseed] {
;#     set rseed [expr ([pid]+[file atime /dev/kmem])%$max]
;#   }
;#   set rseed [expr ($rseed*7141+54773)%$max]
;#   return [expr $rseed%[lindex $args 0]]
;# }

##+#########################################################################
## 
## Legal_1
## 
## Tests whether cell R,C is legal as a first move for player WHO. The
## cell must be in range, contain a WHO blob and can has a place to
## move.
## 
proc legal_1 {r c who} {
    global bb

    set xy [index $r $c]
    if {[lindex $bb $xy] != $who} { return 0 }  ;# Is correct piece there?
    
    foreach i {1 2 9 10 11 12 13 20 21 22 23 24} {;# Neighbors 1 & 2 cells away
        if {[lindex $bb [expr $xy + $i]] == 0} { return 1}
        if {[lindex $bb [expr $xy - $i]] == 0} { return 1}
    }

    return 0
}
##+#########################################################################
## 
## Legal_2
## 
## Tests whether cell R,C is legal as a second move.
## Already we know the cell is empty, so we must check that
## its within 2 of the from cell.
## 
proc legal_2 {r c fr fc} {

    set dr [expr abs($r - $fr)]
    if {$dr > 2} { return 0 }
    set dc [expr abs($c - $fc)]
    if {$dc > 2} { return 0 }

    if {$dr == 2 || $dc == 2} { return 2}
    return 1
}
##+#########################################################################
## 
## Mouse_down
## 
## Called on a mouse down event. Handles moving pieces and checking
## legality.
## 
proc mouse_down {x y} {
    global state bb

    set r [expr $y / $state(cs)]
    set c [expr $x / $state(cs)]
    set where [list $r $c]

    set xy [index $r $c]                        ;# Index into board string
    set cell [lindex $bb $xy]                   ;# What's in that cell
    
    if {$cell == $state(turn)} {
        highlight -1 -1                         ;# Turn off highlight
        if {$state(state) == 1 && $state(from) == $where} {;# Same cell???
            set state(state) 0                  ;# Then toggle it off
            return
        }
        if [legal_1 $r $c $state(turn)] {       ;# Legal to go here?
            highlight $r $c
            set state(state) 1                  ;# Go into next state
            set state(from) $where
            return
        }
    }
    if {$state(state) != 1} return              ;# No selected cell yet
    if {$cell != 0} return                      ;# Not an empty cell

    set n [eval legal_2 $where $state(from)]    ;# Is it legal?
    if $n {                                     
        eval do_move $where $state(from) $n     ;# Yep, so do the move
    } else {
        highlight -1 -1                         ;# Turn off highlighting
    }
    set state(state) 0                          ;# Back to normal state

}
##+#########################################################################
## 
## Do_move
## 
## Does the move from FR,FC to R,C. Updates the blobs, toggles any
## neighbors of the new cell and checks for end-of-game, and can move?
##
proc do_move {r c fr fc type} {
    global state bb mm

    set mm($state(n)) [list $state(turn) $r $c $fr $fc $type];# Undo info
    incr state(n)
    
    set who $state(turn)
    set opp [expr 3 - $who]
    
    highlight -1 -1                             ;# Turn off highlighting
    if {$type != -1} {
        grow_blob $state(turn) $r $c            ;# Put in new blob
        set cnt [toggle_cells $r $c $state(turn)];# Turn things around
        incr state(sc,$who) $cnt                ;# I get more pips
        incr state(sc,$opp) [expr -$cnt]        ;# You get less
    
        if {$type > 1} {                        ;# Long jump???
            delete_blob $fr $fc                 ;# ...then delete old blob
        } else {
            incr state(sc,$who)                 ;# One more for me
            incr state(sc,0) -1                 ;# One less empty
        }
        set bb [lreplace $bb 121 123 $state(sc,0) $state(sc,1) $state(sc,2)]
        update
    }
    
    if {$state(sc,0) == 0 || $state(sc,1) == 0 || \
            $state(sc,2) == 0} {                ;# No more empty cells
        end_game
        return
    }
    
    set mv [can_move $opp]                      ;# Can opponent move?
    if {$mv == 0} {                             ;# How many legal moves?
        set state(msg) "$state(c,$opp) can't move. "
        set state(msg) "$state(msg) $state(c,$who)'s turn"
    } else {
        set state(turn) $opp
        .c itemconfig center -fill $state(c,$state(turn))
    }
    update
    if {$state($state(turn))} robot             ;# Do the computer move
}
##+#########################################################################
## 
## Toggle_cells
## 
## Turns all neighbors of R,C of into WHO blobs
## 
proc toggle_cells {r c who} {
    global bb
    
    set opp [expr 3 - $who]                     ;# The other guy
    set cnt 0                                   ;# How many flipped

    set xy [index $r $c]
    foreach i {1 -1 10 -10 11 -11 12 -12} {     ;# Immediate neighbors
        set p [expr $xy + $i]
        if {[lindex $bb $p] == $opp} {          ;# Is it the opponent?
            delete_blob $p                      ;# Yep, flip him
            make_blob $who $p
            incr cnt
        }
    }

    return $cnt
}
##+#########################################################################
## 
## Can_move 
## 
## Determines if WHO has a legal move
## 
## 
proc can_move {who} {
    global state bb

    for {set r 0} {$r < 7} {incr r} {           ;# Look at each row
        for {set c 0} {$c < 7} {incr c} {       ;# ...and each column
            set xy [index $r $c]
            if {[lindex $bb $xy] != $who} continue

            if [legal_1 $r $c $who] {
                return 1
            }
        }
    }
    return 0                                    ;# Can't move
}
##+#########################################################################
## 
## End_game
## 
## Handles end-of-game stuff
## 
proc end_game {} {
    global state

    if {$state(sc,0) != 0} {                    ;# Shut out
        fill_board [expr ($state(sc,1) > $state(sc,2)) ? 1 : 2]
    }
    
    if {$state(sc,1) > $state(sc,2)} {          ;# Player 1 won
        set state(msg) "Game over: $state(c,1) won"
    } elseif {$state(sc,2) > $state(sc,1)} {    ;# Player 2 own
        set state(msg) "Game over: $state(c,2) won"
    } else {
        set state(msg) "Game over: it's a tie"
    }

    #if $state(Verbose) {
        ##puts "total calls: $state(tc)"
    #}
}
##+#########################################################################
## 
## Index
## 
## Given row, column returns the corresponding index into the board
## string
## 
proc index {r c} {
    return [expr 24 + 11*$r + $c]
}
proc rindex {i} {
    set r [expr ($i / 11) - 2]
    set c [expr ($i % 11) - 2]

    return [list $r $c]
}
##+#########################################################################
## 
## Undo
## 
## Undo last move. Works by replaying all but the last moves.
## 
proc undo {} {
    global state mm bb

    if {$state(n) == 0} {
        set state(msg) "Nothing to undo"
        return
    }
    set state(msg) "Undoing last move"
    set brd $state(init)                        ;# Starting position
    set n [expr $state(n) - 1]                  ;# Number of moves to undo
    set w [lindex $mm($n) 0]                    ;# Who made last turn
    if {$state($w)} {                           ;# Last move by computer
        incr n -1                               ;# So undo both moves
        set w [expr 3 - $w]                     ;# Whose turn it is
    }
    
    for {set i 0} {$i < $n} {incr i} {          ;# Re-do each move
        set brd [eval move2 [list $brd] $mm($i)]
    }

    set state(n) $n                             ;# New count total
    set bb $brd                                 ;# New board
    redraw_board                                ;# Redraw it

    set state(state) 0
    highlight -1 -1
    set state(turn) $w
    .c itemconfig center -fill $state(c,$state(turn))
}
##+#########################################################################
## 
## Robot
## 
## Moves the pieces for the robot player. Does a game-tree search for
## the best move.
## 
proc robot {{level -1}} {
    global state bb

    set who $state(turn)                        ;# Who to move
    if {$level == -1} {
        set level [.level get]                  ;# How smart to be
    }

    if {$level == 0} {                          ;# Random skill level
        set m [lindex [all_moves $who $bb] 0]
    } else {
        set state(c) 0
        set state(msg) "Thinking ($level)" ; update idletasks
        set t [time {set mv [veb $who $bb $level 10000]}];# Get best move
        set state(msg) ""
        if {$state(Verbose)} {
            set tt [expr [lindex $t 0] / 1000000.0]
            set state(msg) \
                    "Rating: [lindex $mv 0] ($state(c) calls in $tt seconds)"
        }
        incr state(tc) $state(c)
    
        set m [lindex $mv 1]
    }
    eval do_move [rindex [lindex $m 1]] [rindex [lindex $m 0]] [lindex $m 2]
}
##+#########################################################################
## 
## Hint
## 
## Suggest a move
## 
proc hint {{level -1}} {
    global state bb 

    if {$level == -1} {                         ;# Was level specified?
        set level [.level get]                  ;# Nope, read the scale
        if {$level == 0} {                      ;# Level 0 is not a hint
            set level 1
        }
    }
    if {$level == -2} {                         ;# One level up from computer
        set level [expr 1 + [.level get]]
        if {$level > 3} { set level 3 }
    }

    highlight -1 -1                             ;# Turn off any highlighting
    set state(c) 0                              ;# For keeping stats
    set state(msg) "Thinking ($level)" ; update idletasks
    set t [time {set mv [veb $state(turn) $bb $level 10000]}];# Find best move
    set state(msg) ""                           ;# Erase old message
    if {$state(Verbose)} {
        set tt [expr [lindex $t 0] / 1000000.0]
        set state(msg) "Rating: [lindex $mv 0] ($state(c) calls in $tt seconds)"
    }
    
    set m [lindex $mv 1]                        ;# Extract the move
    set from [lindex $m 0]
    set to [lindex $m 1]
    
    eval highlight [rindex $from]
    eval highlight [rindex $to]

}
##+#########################################################################
## 
## All_moves
## 
## Returns a list of all legal moves for WHO on board BRD. Format is
## (from to type).
## 
proc all_moves {who brd} {

    set m ""                                    ;# List of valid moves
    for {set i 24} {$i < 97} {incr i} {         ;# Try all positions
        set c [lindex $brd $i]
        if {$c == 4} {                          ;# Is it a border cell?
            incr i 3                            ;# Yep, skip to next valid cell
            continue
        }
        if {$c != $who} continue                ;# Not correct occupant

        foreach j {1 10 11 12 -1 -10 -11 -12} { ;# Immediate neighbors
            set xy [expr $i + $j]
            if {[lindex $brd $xy] == 0} {
                lappend m [list $i $xy 1]
                set brd [lreplace $brd $xy $xy -1];# So we don't go here twice
            }
        }
        foreach j {2 9 13 20 21 22 23 24} {     ;# Neighbors 2 away
            if {[lindex $brd [expr $i + $j]] <= 0} {
                lappend m [list $i [expr $i + $j] 2]
            }
            if {[lindex $brd [expr $i - $j]] <= 0} {
                lappend m [list $i [expr $i - $j] 2]
            }
        }
    }

    set n [llength $m]
    if {$n == 0} {                              ;# Empty list
        return {{0 0 -1}}
    }
    set n [rand $n]
    set m "[lrange $m $n end] [lrange $m 0 [expr $n - 1]]"

    return $m
}
##+#########################################################################
## 
## Move
## 
## Returns new board with WHO moving FROM to TO on board BRD.
## Does no screen updates.
##
proc move {who brd frm to type} {

    if {$type == -1} { return $brd }            ;# Nop move
    
    set opp [expr 3 - $who]                     ;# Opponent
    set sw [lindex $brd [expr 121 + $who]]
    set so [lindex $brd [expr 121 + $opp]]
    
    set brd [lreplace $brd $to $to $who]        ;# Put new blob in
    if {$type == 2} {
        set brd [lreplace $brd $frm $frm 0]     ;# Remove old piece
    } else {
        incr sw                                 ;# Added to WHO's score
        set e [lindex $brd 121]                 ;# Empty spots
        set brd [lreplace $brd 121 121 [expr $e - 1]]
    }

    foreach i {1 10 11 12 -1 -10 -11 -12} {     ;# Immediate neighbors
        set xy [expr $to + $i]
        if {[lindex $brd $xy] == $opp} {        ;# Is it opponent?
            set brd [lreplace $brd $xy $xy $who];# Yep, so toggle it
            incr sw                             ;# Increase WHO's score
            incr so -1                          ;# Decrease OPP's score
        }
    }

    if {$who == 1} {
        set brd [lreplace $brd 122 123 $sw $so]
    } else {
        set brd [lreplace $brd 122 123 $so $sw]
    }

    return $brd
}
proc move2 {brd who r c fr fc type} {
    set b [move $who $brd [index $fr $fc] [index $r $c] $type]
    return $b
}
##+#########################################################################
## 
## E
## 
## Evaluates a position for WHO
## 
proc e {who brd} {

    set me  [lindex $brd [expr 121 + $who]]
    set you [lindex $brd [expr 124 - $who]]

    if {$you == 0} { return  10000 }
    if {$me == 0}  { return -10000 }
    return [expr $me - $you]
}
##+#########################################################################
## 
## Veb
## 
## Game-tree search with alpha-beta pruning. See _Fundamentals of Data
## Structures_, Horowitz, page 268.
##
## Initial call: veb (who board level infinity)
## 
proc veb {who brd l d} {
    global state

    incr state(c)                               ;# Stats
    if {$l == 0 || [lindex $brd 121] == 0} {    ;# Terminal position?
        return [e $who $brd]                    ;# ...just evaluate position
    }

    set ans -10000                              ;# Lower bound on value
    set best ""                                 ;# Current best move

    incr l -1                                   ;# Go down a level
    set moves [all_moves $who $brd]             ;# Get all legal moves
    foreach m $moves {                          ;# Try each possible move
        set b [eval move $who [list $brd] $m]   ;# Do the move
        set e [veb [expr 3 - $who] $b $l [expr -$ans]]
        set a [expr -[lindex $e 0]]

        if {$a > $ans} {                        ;# Is it a better move?
            set ans $a                          ;# Yep, so use it
            ##set best "[list $m] [lrange $e 1 end]"
            set best [list $m]
        }
        if {$ans >= $d} break                   ;# BETA rule
    }

    return "$ans $best"
}
#######################################################################
#
# Draw_menus
#
# Displays the menus on the screen
#
proc draw_menus {} {
    global state

    set menu(0) {&Game &Hint &Undo - &Restart "&New Board" - &Quit}
    set menu(1) {&Opponent "&Red - Computer" "&Green - Computer" - \
            &Random &Greedy &Brainy G&enius}
    set menu(2) {&Display &Grid &Verbose}
    set menu(3) {&Help &Help - &About}
    foreach w [winfo children .m] {             ;# Destroy what's out there 
        catch { destroy $w }
    }

    .m config -bd 3 -relief ridge               ;# Configure its window 

    set menubar .m                              ;# Who to add to tk_menuBar 
    for {set i 0} {[info exist menu($i)]} {incr i} {
        set who [underline [lindex $menu($i) 0]];# Menu header
        set u [lindex $who 0]                   ;# Underline
        set who [lrange $who 1 end]
        
        menubutton .m.m$i -text $who -menu .m.m$i.m -padx 5 \
                -underline $u -relief raised
        menu .m.m$i.m

        foreach item [lrange $menu($i) 1 end] {   ;# Add sub-commands
            set item [underline $item]
            set u [lindex $item 0]
            set item [lrange $item 1 end]
            
            if [string match $item "-"] {
                .m.m$i.m add separator
            } elseif [string match $who "Opponent"] {
                if {[llength $item] > 1} {
                    set w 2
                    if [string match [lindex $item 0] "Red"] {
                        set w 1
                    }
                    .m.m$i.m add check -label $item -u $u \
                            -variable state($w) \
                            -command "do_menu $who $item"
                } else {
                    .m.m$i.m add radio -label $item -u $u \
                            -variable state(skill) \
                            -command "do_menu $who $item"
                }
            } elseif [string match $who "Display"] {
                .m.m$i.m add check -label $item -u $u \
                        -variable state($item) \
                        -command "do_menu $who $item"
            } else {
                .m.m$i.m add command -label $item -underline $u \
                        -command "do_menu $who $item"
            }
        }
        pack .m.m$i -side left                  ;# Display it 
        lappend menubar .m.m$i
    }
    eval tk_menuBar $menubar                    ;# Make available via keyboard
    focus [lindex $menubar 0]                   ;# Focus on the menubar
}
#######################################################################
#
# Underline
#
# Determines where in a menu item the underline should be placed. It
## goes after the '&' in the item.
#
# Value:  it&em => "1 item"
#         &item => "0 item"
#         item  => "-1 item"
#
proc underline item {
    set u [string first & $item]
    if {$u != -1} {
        if {$u == 0} { 
            set item [string range $item 1 end]
        } else { 
        set item [string range $item 0 [expr $u - 1]][string range $item \
                [expr $u + 1] end]
        }
    }

    return "$u $item"
}
#######################################################################
#
# Do_menu
#
# Process the menu commands
#
proc do_menu {cmd option args} {
   global state

    set option [string tolower $option]         ;# Lowercase the arguments  
    switch $cmd {
        Help -
        Game { 
            switch $option {                    
                hint { hint }
                undo { undo }
                restart { new_board $state(brd) ; start}
                new { new_board ; start }
                quit { exit }
                
                about {
                    set msg "TkAtaxx\n\nby Keith Vetter\[EMAIL PROTECTED]"
                    my_dialog .about About $msg 3i
                }
                help { help }
            }
        }
        Opponent {
            set n [lsearch "random greedy brainy genius" $option]
            if {$n != -1} {
                .level set $n
            } else start
        }
        Display  { if {$option == "grid"} grid }
    }
}
##+#########################################################################
## 
## Start
## 
## Starts/continues the game if it's the computer's turn
## 
proc start {} {
    global state

    if {$state(sc,0) == 0 || $state(sc,1) == 0} return
    if {$state($state(turn)) == 1} robot
}
##+#########################################################################
## 
## Help
## 
## Displays a help screen using a modified version of tk_dialog
## 
proc help {} {
    set msg ""
    set msg "TkAtaxx\n\n\n"
    set msg "${msg}DESCRIPTION"
    set msg "$msg\n\nTkAtaxx is a tcl/tk implementation of the popular"
    set msg "$msg arcade video Ataxx. The goal of the game is end up"
    set msg "$msg with more pieces of your color than your"
    set msg "$msg opponent. The game ends when there are no more"
    set msg "$msg places to move."

    set msg "$msg\n\nMOVING"
    set msg "$msg\n\nYou can move a piece in two different ways, either"
    set msg "$msg sliding or jumping.  To slide a piece, click on it"
    set msg "$msg with the mouse, then click on an immediately"
    set msg "$msg adjacent empty cell. The piece will split and"
    set msg "$msg occupy both cells. To jump a piece, click on it"
    set msg "$msg with the mouse, then click on an empty cell which"
    set msg "$msg is two positions away from the starting piece. The"
    set msg "$msg piece will jump to the new position over any"
    set msg "$msg intervening obstacles vacating the original"
    set msg "$msg position. If there are no possible moves for a"
    set msg "$msg player then the move if forfeited."
    set msg "$msg\n\nWhen a piece moves to a new cells, all surrounding"
    set msg "$msg cells of the opponent's color will be captured and"
    set msg "$msg turn into your color."

    set msg "$msg\n\nSKILL LEVEL"
    set msg "$msg\n\nYou can adjust how smart the computer opponent"
    set msg "$msg is. Random skill picks any move at"
    set msg "$msg random. Greedy picks the move which maximizes how"
    set msg "$msg many pieces he has at the end of the turn. Brainy"
    set msg "$msg searches two moves ahead of the best move. Genius"
    set msg "$msg searches three moves ahead for the best move."

    set msg "$msg\n\nProgram written by Keith Vetter ([EMAIL PROTECTED])"

    my_dialog .top Help $msg 6i
}
##+#########################################################################
## 
## My_dialog
## 
## Simplified version of tk_dialog. Forced to so we could better
## adjust the width of the dialog.
## 
proc my_dialog {w title text width} {
    global tk_priv

    # 1. Create the top-level window and divide it into top
    # and bottom parts.

    catch {destroy $w}
    toplevel $w -class Dialog
    wm title $w $title
    wm iconname $w Dialog
    frame $w.top -relief raised -bd 1
    pack $w.top -side top -fill both
    frame $w.bot -relief raised -bd 1
    pack $w.bot -side bottom -fill both

    # 2. Fill the top part with bitmap and message.

    message $w.msg -text $text -font -Adobe-Times-Medium-R-Normal-*-180-*
    $w.msg config -width $width
    pack $w.msg -in $w.top -side right -expand 1 -fill both -padx 5m -pady 5m
    label $w.bitmap -bitmap info
    pack $w.bitmap -in $w.top -side left -padx 5m -pady 5m

    # 3. Create a row of buttons at the bottom of the dialog.

    frame $w.default -relief sunken -bd 1
    button $w.button -text " OK " -command "destroy $w"
    pack $w.default -in $w.bot -side left -expand 1 -padx 3m -pady 2m
    pack $w.button -in $w.default -padx 2m -pady 2m -ipadx 2m -ipady 1m

    # 4. Withdraw the window, then update all the geometry information
    # so we know how big it wants to be, then center the window in the
    # display and de-iconify it.

    wm withdraw $w
    update idletasks
    set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
            - [winfo vrootx [winfo parent $w]]]
    set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
            - [winfo vrooty [winfo parent $w]]]
    wm geom $w +$x+$y
    wm deiconify $w

    return
}
##+#########################################################################
## 
##
init
display
new_board
set state(msg) "Welcome to TkAtaxx"

wm minsize . 300 300
update
;#BROKEN bind . <Configure> { resize %w %h }


proc dump {{brd ""}} {
    global bb

    if {$brd == ""} {set brd $bb}
    for {set i 0} {$i < 11} {incr i} {
        for {set j 0} {$j < 11} {incr j} {
            if {$j == 2 || $j == 9} { puts -nonewline " "}
            puts -nonewline "[lindex $brd [expr $i*11 + $j]] "
        }
        if {$i == 1 || $i == 8} {puts " "}
        puts " "
    }
}


proc foo {} {
    global bb

    set e [lindex $bb 121]
    set r [lindex $bb 122]
    set g [lindex $bb 123]
    set o [lindex $bb 124]

    set t [expr $e + $r +$g + $o]
    puts "e $e  r $r  g $g  o $o   $t"
}


set xbb "4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 0 0 1 3 1 2 2 4 4 4 4 0 1 1 1 
1 1 0 4 4 4 4 0 3 1 1 1 3 0 4 4 4 4 3 1 1 1 1 1 3 4 4 4 4 1 3 1 1 1 3 1 4 4 4 4 0 1 1 
1 1 1 1 4 4 4 4 1 0 1 3 1 1 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 7 32 2 8"

return

Répondre à