Markov Chain

Markov Chain

# Markov Chains in Tcl
 set CelticFemale { Aberfa Abertha Abiageal Adain Adair Adaira Adairia Adara Addfwyn Addien Addiena Adeen Adenydd Aderyn Adyna Aelwen Aelwyd Aerona Aghadreena Aghamóra Aghaveagh Aghavilla Aghna Aigneis Aila Aileana Aileen Aileene Ailey Aili Ailia Ailin Ailis Ailisa Ailise Ailsa Aine Aingeal Ainsley Aisling Akira Alaina Alaine Alana Alani Alanna Alannah Alastrina Alastrióna Alayna Alexina Alina Alison Aliyn Allana Allene Allisón Allsun Allsún Alma Alona Alónna Alpina Alvy Alysón Amser Anchoret Anghard Anice Ann Annabel Annabella Annabla Ansley Anwen Aoibheann Aóibheann Aoife Aóife Ardala Argel Argíwyddes Argoel Argraff Arial Arian Ariana Arianrhod Arianwyn Ariyne Arlais Arleen Arlena Arlene Arleta Arlette Arline Arliss Armes Artaith Arthes Arwydd Asgre Ashling Assana Assane Atgas Athdara Augusteen Aúgusteen Aurnia Aúrnia Avonmóra Awel Awen Awena Baibre Banón Barran Beathas Bebhinn Berneen Berth Berthóg Bethan Betrys Bidelia Bidina Blair Blaire Blód Blodwen Blodwyn Blyana Bonni Bonnie Bradana Braith Brangwen Brangwy Brann Branwen Branwenn Branwyn Brea Breandan Breanne Breck Bree Breeda Breen Breena Bregus Brenda Brendalynn Brendólyn Brenna Bria Briallan Briallen Briana Brianna Brianne Briar Brid Bride Bridget Brielle Brighid Brina Bróna Bronwen Bronwyn Bryanna Bryna Brynda Búddug Cacey Cacia Cadee Cadence Cadha Cadhla Cadi Cadie Cadwyn Cady Caethes Cafell Caffara Caffaria Cahira Cai Cailin Cailleach Caillic Cait Caitie Caitlan Caitland Caitlin Caitlinn Caitlyn Caitlynn Caitrin Callahan Callee Calli Callie Cambree Cameron Camerón Campbell Caniad Caóimhe Cara Caraf Caraid Carleen Carlin Carolan Caroline Caron Carroll Carys Casee Casey Casidhe Cassidy Cat Catelyn Cath Catharine Cathasach Cathleen Cathryn Catlee Catlin Catline Catlyn Catrin Catriona Catrióna Cattee Cavana Caycee Ceire Ceri Ceridwen Chiara Chrissa Chrissie Chrissy Christa Christal Christel Christi Christian Christie Christy Ciara Ciatlllait Cleónie Clodagh Codee Codi Cody Coira Cólene Colina Colleen Collena Cóllene Colmcilla Comyna Cóncepta Conchóbara Conchóbarra Conchóbarre Congalie Connal Connelly Cora Cordelia Coreen Córeene Coretta Córey Cori Coriann Corianne Corie Corisa Correen Córreena Corri Corrianna Córrianne Corrie Córry Corsen Cory Cragen Creiddylad Crissa Crissie Crissy Cristie Cristin Cristy Cristy Crwys Cúllodena Cullódina Cúmania Cúmina Cymreiges Daere Dallas Dallis Dana Daracha Darby Darcel Darcell Darcelle Darcey Darchelle Darci Darcia Darcie Darcy Darerca Dearbhail Decla Dedre Dee Deedra Deidra Deidre Deirdra Delaney Delia Dera Derforgal Derforgala Derry Derval Dervilia Dervla Dervórgilla Derwen Devaney Devanie Devany Devenny Devent Devinee Devnet Devóny Dicra Diedre Dierdre Difyr Dilys Doireann Dominica Dónelle Doon Doreen Dówneti Downett Drew Drysi Du Dúana Dúayna Dubhain Dúbheasa Dúvessa Dylis Dyllis Dymphna Dympna Eabha Eadan Ealga Earie Eavan Ebrill Edana Edeen Edina Edine Efa Eheúbryd Eibhlhin Eila Eileen Eileene Eilena Eilene Eilinora Eilis Eilwen Eily Eira Eiric Eirica Eirlys Eistir Eithna Eithne Elan Elen Elin Elíylw Elleen Elsbeth Elspeth Elva Elvia Elvie Elvina Elvinia Elwyn Ena Enat Eneuawg Enfys Enid Enit Ennis Enrhydreg Enya Erdúdvyl Eres Erin Erina Erskina Esyílt Etain Ethna Etney Eúrneid Eurolwyn Evanna Eveleen Evina Eyslk Fainche Faline Fallon Fallyn Falón Farran Fearchara Fearcharia Fedelma Feenat Fenella Ffanci Ffraid Fia Fiachina Fiachra Fianait Fidelma Fineena Finella Finna Finnea Finola Fiona Fiónn Fiónna Fionnghúala Fiónnuala Firtha Flanna Gaenor Gaerwen Gaira Gara Garan Garia Gavenia Gavina Gilbarta Gíyn Gíynna Gladis Gladys Glain Glan Glaw Gleda Glenda Glenna Glenys Glinda Glióna Glyn Glynae Glynda Glynn Glynnis Gobnait Góbnat Goewin Goleúddydd Gorasgwrn Górawen Gordana Gordania Górmghlaith Gormley Górmly Graina Grainne Grear Greer Grizel Grizela Gúbnat Guinevere Gúinevere Gúnna Gwaeddan Gwanwyn Gwen Gwenabwy Gwenda Gwendelyn Gwendi Gwendolen Gwendóline Gwendolyn Gwener Gweneth Gwenhwyvar Gwenifer Gwenledyr Gwenllian Gwenna Gwennálarch Gwennan Gwenyth Gwladys Gwylan Gwyn Gwynes Gwyndolen Gwynefar Gwyndolyn Gwynedd Gwyneth Gwynn Gwynne Hafwen Henley Hennessy Heúlwens Hiólair Hisólda Honor Honóra Hónoria Ibernia Ida Ide Idella Ierne Ilane Indeg Inghean Inghinn Inis Iola Ióna Iórwen Iseabal Isibeal Isla Isleen Islene Isobel Isolda Isólde Ita Izett Jaime Jaimee Jaimelynn Jaimi Jaimie Jamee Jamey Jami Jamia Jamie Jamielee Jamilyn Jamison Jana Janet Janet Janetta Jannet Janneth Jaymee Jaymie Jean Jen Jenifer Jennifer Jestina Jestine Jinelle Kady Kaitlan Kaitleen Kaitlin Kaitlyn Kaitlynn Kallie Kamerón Kasey Kasie Kathleen Kathleena Kathlene Kathlynn Keana Keanna Keara Kearney Keavy Keeley Keely Keelyn Keenat Keiana Keilah Keira Kelcie Kelcy Kelemón Kelleigh Kelley Kelli Kellsey Kellyanne Kellye Kellyn Kelsee Kelsey Kelsi Kenzie Kenzy Kera Keri Keriana Keriann Kerianna Kerianne Kerilyn Kerra Kerri Kerrianne Kerrie Kerry Kevay Kiahna Kiana Kiandra Kiandria Kiani Kianna Kianni Kiara Kiauna Kiera Kigva Kinnat Kiona Kiónah Kioni Kionna Kyla Labhaoise Laetitia Lainie Lair Laire Laoghaire Laóghaire Lara Laren Larena Laria Leana Leena Leila Leslee Leslie Levane Lezlie Liadan Lil Lilybet Lindsay Linsey Lioslaith Logan Lógan Lorna Lowri Lówri Lúighseach Lyndsey Lynelle Lynessa Lyneth Lynette Lynnet Lynnette Mabbina Mabli Mabli Mabyn Machara Mada Madailein Maegan Maeryn Maeve Maggie Maible Maighdlin Maille Mailsi Mair Maira Maire Mairead Mairi Mairia Mairona Mairwen Maisie Maiti Maitilda Maitilde Maive Majella Mali Malmúira Malmuirie Malvina Maóla Maoli Marcail Maredúd Marella Margaret Marged Margred Mari Marilla Maud Maúde Maúra Maureen Maúrine Maurya May Maygan Mayra Mckenna Meadhbh Meagan Meaghan Mearr Meeda Meeghan Megdn Meggan Meghan Meghan Melangell Melva Mercia Meredith Meredydd Mererid Merna Minna Módlen Moibeal Moina Moira Moire Moireach Molli Mona Monca Morcan Moreen Morella Morgaine Morgan Morgana Morgann Morgant Morgayne Morna Morrin Morvúdd Morwen Morwenna Morwyn Moya Móyna Múadhnait Muira Múire Múireann Muirgheal Múirne Murel Múriel Myfanawy Myma Nainsi Nairna Nairne Nairne Nathaira Nathara Neala Nelda Nerys Nessa Nessia Neúed Nighean Nighinn Noreen Nóreena Nuala Núala Oíwyna Olive Olwen Olwina Olwyn Oma Omat Ona Onóra Oona Oónagh Orghlaith Orla Orlaith Owena Penarddún Phiala Raicheal Raoghnailt Raoghnailt Rathnait Rathtyen Renny Rhan Rhawn Rhedyn Rhiain Rhian Rhiannon Rhianwen Rhianwyn Rhonwen Rhóslyn Rhosyn Rianna Richael Rioghnach Rióna Robena Robina Rois Ronda Rose Sabia Sadhbba Sadhbh Saeran Saeth Saffir Saoirse Saraid Sarff Scóta Seana Seren Shaelan Shanessa Shauna Shaúna Shawn Shea Sheelah Sheila Sheridan Sian Siany Sibeal Sierra Sile Sileas Sima Sine Sinead Sineidin Siobhan Sióbhan Sioned Siusan Sive Skena Slaine Slany Sloan Sórcha Sosanna Strúana Súbhan Sulwyn Sybil Talaith Talar Tangwen Tara Tarian Tarren Tate Tavia Tawnee Tawney Tawni Tawnia Tawnie Tawny Tawnya Teagan Teamhair Tegan Teige Teleri Telyn Telyn Terrwyn Teva Tierney Tipper Tira Toireasa Tóreth Torey Torlan Tórra Torree Torri Tóry Treasa Treise Tristyn Tullia Túllia Tyra Ulicia Una Unity Uny Vala Valmai Vanóra Vevila Vevina Vika Wenda Wendi Wendy Winifred Winnie Winnifred Wyn Wynda Wynne Wynnifred Ysbail Zaira }

 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 linklens {3 2}
 set minlen 999
 # prevent too many consonants or vowels appearing
 set maxconsonants 2
 set maxvowels 3
 puts ""

 # Set up markov chain transitions
 foreach linklen $linklens {
   if {$linklen<$minlen} {set minlen $linklen}
   incr linklen -1
   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