## Markov Chain

Markov Chain

```# Markov Chains in Tcl

set matrix [dict create]
# use a "fallback" such that there are tables for both 3 and 2
# make generator more robust, but may still fallback to trying again
# if no transition can be found
set minlen 999
# prevent too many consonants or vowels appearing
set maxconsonants 2
set maxvowels 3
puts ""

# Set up markov chain transitions
foreach name \$CelticFemale {
set name "![string tolower \$name]@"
for {set i 0} {\$i < ([string length \$name]-\$linklen-1)} {incr i} {
set letters [string range \$name \$i \$i+\$linklen]
set nextch [string index \$name [expr {\$i+\$linklen+1}]]
if {[catch {set index [dict get \$matrix \$letters]}]!=0} {set index [dict create]}
dict incr index \$nextch
dict incr index total
dict set matrix \$letters \$index
}
}
}
set start {}
foreach key [dict keys \$matrix] {if {[string index \$key 0] eq "!"} {lappend start \$key}}

# Generate text
proc gen {{maxlen 12}} {
global start matrix CelticFemale minlen maxconsonants maxvowels
set segment [lindex \$start [expr {int(rand()*[llength \$start])}]]
set result [string range \$segment 1 end]
while 1 {
if {[catch {set choices [dict get \$matrix \$segment]}] != 0} {
#return -[string toupper \$result 0 0]
#tailcall gen
#return [lindex \$CelticFemale [expr {int(rand()*[llength \$CelticFemale])}]]
set segment [string range \$segment 1 end]
if {[string length \$segment]>=\$minlen} continue
return [lindex \$CelticFemale [expr {int(rand()*[llength \$CelticFemale])}]]
}
set max [dict get \$choices total]
dict unset choices total
set choice [expr {int(rand()*\$max)}]
dict for {letter number} \$choices {
incr choice -\$number
if {\$choice <= 0} {
if {\$letter eq "@"} {return [string toupper \$result 0 0]}
set result "\$result\$letter"
if {[string length \$result]>\$maxlen} {tailcall gen \$maxlen}
set consonants ""; regexp {[bcdfghjklmnpqrstvwxz]+} \$result -> consonants
if {[string length \$consonants]>\$maxconsonants} {tailcall gen \$maxlen}
set vowels ""; regexp {[aáeiíoóuúy]+} \$result -> vowels
if {[string length \$vowels]>\$maxvowels} {tailcall gen \$maxlen}
set segment [string range \$result end-2 end]
}
}
}
}

for {set i 0} {\$i < 10} {incr i} {puts [gen]}
exit```