Based on comprehensive exploration of the help command, Feather TCL provides all necessary primitives to implement Conway's Game of Life. This document catalogs available commands and provides an implementation strategy.
list- Create a listlindex <list> <index>- Retrieve an element from a listllength <list>- Return the number of elements in a listlappend <varName> ?value...?- Append list elements onto a variablelset <varName> <index> <value>- Change an element in a listlinsert <list> <index> ?element...?- Insert elements into a listlrange <list> <first> <last>- Return one or more adjacent elements from a listlreplace <list> <first> <last> ?element...?- Replace elements in a listlrepeat <count> ?element...?- Build a list by repeating elementslreverse <list>- Reverse the elements of a listlsort <list>- Sort the elements of a listlsearch <list> <pattern>- See if a list contains a particular elementlmap <varname> <list> <body>- Map a script over one or more listslassign <list> <varName> ?varName...?- Assign list elements to variables
dict create ?key value...?- Manipulate dictionariesdict get <dict> <key>- Get value from dictionarydict set <dictVar> <key> <value>- Set value in dictionarydict exists <dict> <key>- Check if key existsdict keys <dict>- Get all keysdict values <dict>- Get all valuesdict size <dict>- Get number of entriesdict for <keyVar> <valueVar> <dict> <body>- Iterate over dictionary
for <start> <test> <next> <body>- 'For' loop- Example:
for {set i 0} {$i < 10} {incr i} { ... }
- Example:
while <test> <body>- Execute script repeatedly as long as a condition is metforeach <varname> <list> <body>- Iterate over all elements in one or more listsbreak- Abort looping commandcontinue- Skip to the next iteration of a loop
if <expr> <body> ?elseif <expr> <body>...? ?else <body>?- Execute scripts conditionallyswitch <string> ?pattern body...?- Evaluate one of several scripts, depending on a given value
proc <name> <args> <body>- Create a TCL procedurereturn ?-code code? ?value?- Return from a procedureapply <lambda> ?arg...?- Apply an anonymous function- Lambda format:
{args body ?namespace?}
- Lambda format:
uplevel ?level? <script>- Execute a script in a different stack frameupvar ?level? <otherVar> <myVar>- Create link to variable in a different stack frame
set <varName> ?value?- Read and write variablesglobal <varName> ?varName...?- Access global variablesvariable <name> ?value?- Create and initialize a namespace variableunset ?-nocomplain? ?varName...?- Delete variablesincr <varName> ?increment?- Increment the value of a variableappend <varName> ?value...?- Append to variable
-
expr <arg> ?arg...?- Evaluate an expression- Supports:
+,-,*,/,%(modulo) - Comparisons:
<,<=,>,>=,==,!= - Logical:
&&,||,! - Bitwise:
&,|,^,~,<<,>> - Parentheses for grouping
- Mathematical functions available via
tcl::mathfunc::
- Supports:
-
incr <varName> ?increment?- Increment the value of a variable (efficient for +1/-1)
string length <string>- Get string lengthstring index <string> <index>- Get character at indexstring range <string> <first> <last>- Get substringstring repeat <string> <count>- Repeat stringstring replace <string> <first> <last> ?newstring?- Replace substringstring cat ?string...?- Concatenate stringsstring match <pattern> <string>- Pattern matching with wildcardsstring equal <str1> <str2>- String equalitystring compare <str1> <str2>- String comparisonstring map <mapping> <string>- Map characters/substringsformat <formatString> ?arg...?- Format a string in the style of sprintfscan <string> <format> ?varName...?- Parse string using conversion specifiersjoin <list> ?separator?- Create a string by joining list elementssplit <string> ?splitChars?- Split string into list elements
eval <arg> ?arg...?- Evaluate a Tcl scriptsubst ?-nobackslashes? ?-nocommands? ?-novariables? <string>- Perform substitutionscatch <script> ?varName?- Evaluate script and trap exceptional returnserror <message> ?info? ?code?- Generate an errortry <body> ?on code varList handler...? ?finally script?- Trap and process errors
info commands ?pattern?- List available commandsinfo exists <varName>- Check if variable existsinfo globals ?pattern?- List global variablesinfo locals ?pattern?- List local variablesinfo vars ?pattern?- List all visible variablesinfo procs ?pattern?- List defined proceduresinfo args <procname>- Get procedure argumentsinfo body <procname>- Get procedure body
Grid as List of Lists
# 10x10 grid initialized to 0 (dead cells)
proc create_grid {width height} {
set grid [list]
for {set y 0} {$y < $height} {incr y} {
set row [lrepeat $width 0]
lappend grid $row
}
return $grid
}
# Get cell value
proc get_cell {grid x y} {
set row [lindex $grid $y]
return [lindex $row $x]
}
# Set cell value
proc set_cell {gridVar x y value} {
upvar $gridVar g
set row [lindex $g $y]
set row [lreplace $row $x $x $value]
set g [lreplace $g $y $y $row]
}# Count live neighbors (8-directional)
proc count_neighbors {grid x y width height} {
set count 0
for {set dy -1} {$dy <= 1} {incr dy} {
for {set dx -1} {$dx <= 1} {incr dx} {
if {$dx == 0 && $dy == 0} continue
set nx [expr {$x + $dx}]
set ny [expr {$y + $dy}]
# Boundary check
if {$nx >= 0 && $nx < $width && $ny >= 0 && $ny < $height} {
set cell [get_cell $grid $nx $ny]
set count [expr {$count + $cell}]
}
}
}
return $count
}
# Apply Conway's rules
proc next_generation {grid width height} {
set new_grid [create_grid $width $height]
for {set y 0} {$y < $height} {incr y} {
for {set x 0} {$x < $width} {incr x} {
set cell [get_cell $grid $x $y]
set neighbors [count_neighbors $grid $x $y $width $height]
# Conway's rules:
# 1. Live cell with 2-3 neighbors survives
# 2. Dead cell with exactly 3 neighbors becomes alive
# 3. Otherwise dies/stays dead
if {$cell == 1} {
# Cell is alive
if {$neighbors == 2 || $neighbors == 3} {
set_cell new_grid $x $y 1
}
} else {
# Cell is dead
if {$neighbors == 3} {
set_cell new_grid $x $y 1
}
}
}
}
return $new_grid
}# Print grid to screen (no puts command, but we have echo)
proc display_grid {grid} {
set output ""
foreach row $grid {
set line ""
foreach cell $row {
if {$cell == 1} {
set line "${line}█"
} else {
set line "${line}·"
}
}
echo $line
}
}
# Alternative using format
proc display_grid_formatted {grid} {
foreach row $grid {
set line [string map {0 "· " 1 "█ "} [join $row ""]]
echo $line
}
}proc run_game_of_life {initial_grid width height generations} {
set grid $initial_grid
for {set gen 0} {$gen < $generations} {incr gen} {
echo "Generation: $gen"
display_grid $grid
echo ""
set grid [next_generation $grid $width $height]
}
}# Glider pattern
proc create_glider {width height} {
set grid [create_grid $width $height]
# Glider at position (1,0)
set_cell grid 2 0 1
set_cell grid 3 1 1
set_cell grid 1 2 1
set_cell grid 2 2 1
set_cell grid 3 2 1
return $grid
}
# Blinker pattern
proc create_blinker {width height} {
set grid [create_grid $width $height]
set mid [expr {$width / 2}]
set_cell grid $mid [expr {$height / 2 - 1}] 1
set_cell grid $mid [expr {$height / 2}] 1
set_cell grid $mid [expr {$height / 2 + 1}] 1
return $grid
}- Lists - Primary data structure (nested lists for 2D grid)
- Dictionaries - For configuration/metadata
- Arithmetic expressions - Full expr support with all operators
- Loops - for, while, foreach
- Conditionals - if/elseif/else, switch
- Procedures - First-class procedures with upvar for pass-by-reference
- String manipulation - Comprehensive string operations
- Increment - Efficient incr command
- List operations - lindex, lset, lreplace, etc.
- No
putscommand - Must useechofor output (test-specific command)- In production, would need to use string building and return values
- No arrays - Feather explicitly doesn't support TCL-style arrays
- Must use lists or dicts instead
- No file I/O visible - No open/close/read/write commands in help
- Likely handled by host, not exposed to TCL level
- No time/sleep commands - Can't add delays between generations
- Would need to be driven externally
- No random - Can't generate random initial states
- Would need to pass in patterns
- Output: Build strings and return them, or use
echoif available - Arrays: Use list of lists (works well for 2D grids)
- File I/O: Not needed for basic simulation
- Animation: External driver can call the simulation repeatedly
- Random: Pre-define patterns or accept them as input
# All procedures are pure functions that take input and return output
proc create_grid {width height} { ... }
proc get_cell {grid x y} { ... }
proc set_cell_value {grid x y value} { ... } # Returns new grid
proc count_neighbors {grid x y width height} { ... }
proc next_generation {grid width height} { ... }proc pattern_glider {} { ... }
proc pattern_blinker {} { ... }
proc pattern_toad {} { ... }
proc pattern_beacon {} { ... }
proc pattern_pulsar {} { ... }proc grid_to_string {grid} { ... } # Returns formatted string
proc display_grid {grid} { ... } # Uses echo if availableproc run_simulation {pattern_name width height generations} { ... }# Complete Conway's Game of Life in Feather TCL
proc create_grid {width height} {
set grid [list]
for {set y 0} {$y < $height} {incr y} {
lappend grid [lrepeat $width 0]
}
return $grid
}
proc get_cell {grid x y} {
lindex [lindex $grid $y] $x
}
proc set_cell_immutable {grid x y value} {
set row [lindex $grid $y]
set row [lreplace $row $x $x $value]
lreplace $grid $y $y $row
}
proc count_neighbors {grid x y width height} {
set count 0
foreach dy {-1 0 1} {
foreach dx {-1 0 1} {
if {$dx == 0 && $dy == 0} continue
set nx [expr {$x + $dx}]
set ny [expr {$y + $dy}]
if {$nx >= 0 && $nx < $width && $ny >= 0 && $ny < $height} {
incr count [get_cell $grid $nx $ny]
}
}
}
return $count
}
proc next_gen {grid width height} {
set new_grid [create_grid $width $height]
for {set y 0} {$y < $height} {incr y} {
for {set x 0} {$x < $width} {incr x} {
set alive [get_cell $grid $x $y]
set n [count_neighbors $grid $x $y $width $height]
if {($alive && ($n == 2 || $n == 3)) || (!$alive && $n == 3)} {
set new_grid [set_cell_immutable $new_grid $x $y 1]
}
}
}
return $new_grid
}
# Test it
set grid [create_grid 5 5]
set grid [set_cell_immutable $grid 1 2 1]
set grid [set_cell_immutable $grid 2 2 1]
set grid [set_cell_immutable $grid 3 2 1]
# Run 3 generations
for {set i 0} {$i < 3} {incr i} {
echo "Generation $i:"
foreach row $grid {
echo [string map {0 "· " 1 "█ "} [join $row " "]]
}
set grid [next_gen $grid 5 5]
}Feather TCL has all the necessary primitives to implement Conway's Game of Life:
- ✅ 2D data structures (list of lists)
- ✅ Arithmetic and comparisons
- ✅ Loops and conditionals
- ✅ Procedures and state management
- ✅ String formatting for display
The main limitation is output (no puts), but echo works for testing, and production code can return formatted strings for the host to display.
The implementation is straightforward and idiomatic TCL, using immutable operations where possible and mutable operations (via upvar) where performance is needed.