#! /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 allMichael 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.