Updated 2014-06-25 05:22:39 by pooryorick

Richard Suchenwirth 2003-04-21: Here is another little Tk game, "Align Four" (in America also known as "Connect Four"), where you drop chips of your color (red or yellow) into slots of a receptacle, until one player has managed to get four chips in a row.

PYK 2014-06-24: Modernized code, replaced update with coroutine.
#! /bin/env tclsh

set info {TkAlign4 - Richard Suchenwirth 2003

Two players, red and yellow.
Click on a column to insert piece.
If you have four pieces in a row
(horizontal, vertical, diagonal), you win.
}

package require Tk

frame .f
button .f.0 -text New   -command {reset .c}
button .f.1 -text Reset -command {reset .c all}
entry  .f.2e -textvar g(pred) -width 8
set g(pred) Player1
label  .f.2 -bg red -width 3 -textvar g(red)
entry  .f.32 -textvar g(pyellow) -width 8
set g(pyellow) Player2
label  .f.3 -bg yellow -width 3 -textvar g(yellow)
button .f.4 -text ? -command {tk_messageBox -message $info}
eval pack [winfo children .f] -side left -fill y
canvas .c
pack {*}[winfo children .]
wm geometry . 240x320+0+0

proc reset {c {what {}}} {
    global g
    if {$what eq {all}} {
        set g(red) 0
        set g(yellow) 0
        set g(toPlay) red
    }
    $c delete all
    $c create oval 107 2 133 28 -fill $g(toPlay) -tag chip
    $c create rect 0 30 240 240 -fill darkblue
    foreach x {0 1 2 3 4 5 6} {
        set x0 [expr {$x * 32 + 10}]
        set x1 [expr {$x0 + 26}]
        foreach y {1 2 3 4 5 6} {
            set y0 [expr {$y * 32 + 16}]
            set y1 [expr {$y0 + 26}]
            set id [$c create oval $x0 $y0 $x1 $y1 -fill black -tag $x,$y]
            set script {}
            #if [inserting] exists, a move is in progress.  Do nothing
            append script {if {[namespace which inserting] ne "[
                string trimright [namespace current] ::]::inserting"} } [list [
                list coroutine inserting insert $c $x]]
            $c bind $id <1> [namespace code $script]
        }
    }
}

proc insert {c x} {
    if {[$c find withtag chip] eq {}} return
    if {[colorof $c $x,1] ne {black}} return
    $c delete chip
    global g
    set color $g(toPlay)
    $c itemconfig $x,1 -fill $color
    set y 1
    while {[colorof $c $x,[expr {$y + 1}]] eq {black}} { 
        $c itemconfig $x,$y       -fill black
        $c itemconfig $x,[incr y] -fill $color
        after 100 [list [info coroutine]]
        yield
    }
    if {![win $c $x $y]} {
        set g(toPlay) [expr {$color eq {red} ? {yellow} : {red}}]
        $c create oval 107 2 133 28 -fill $g(toPlay) -tag chip
    }
}

proc colorof {c tag} {$c itemcget $tag -fill}
proc win {c x y} {
    global g
    set self [colorof $c $x,$y]
    foreach {dx dy} {1 0  0 1  1 1  1 -1} {
        set mdx [expr {-$dx}]; set mdy [expr {-$dy}]
        set row $x,$y
        set x0 $x; set y0 $y
        while {[colorof $c [incr x0 $dx],[incr y0 $dy]] eq $self} {
            lappend row $x0,$y0
        }
        set x0 $x; set y0 $y
        while 1 {
            if {[colorof $c [incr x0 $mdx],[incr y0 $mdy]] ne $self} break
            lappend row $x0,$y0
        }
        if {[llength $row] >= 4} {
            foreach chip $row {$c addtag win withtag $chip}
            $c itemconfig win -fill green
            after 1000 $c itemconfig win -fill $self
            set g(toPlay) [expr {$self eq {red} ? {yellow} : {red}}]
            tk_messageBox -message "$g(p$self) wins" 
            incr ::g($self)
            return 1
        } 
    }
    return 0
}
reset .c all

Michael Jacobson and Jason Tang have produced an enhanced version that has auto-play facility (5 levels of difficulty) and runs well on a PocketPc. See the iConnect4 page for this version.

Velena is a sophisticated free AI engine which plays connect four perfectly.

Theoretical details on how to show that the game is a first player win are presented in A Knowledge-based Approach of Connect-Four, L. Victor Allis, 1989.

Detailed explanations of Velena can be found in Searching for Solutions in Games and Artificial Intelligence, Allis, 1994.