1" Macros to play Conway's Game of Life in vi 2" Version 1.0m: edges wrap 3" by Eli-the-Bearded Benjamin Elijah Griffin <[email protected]> 4" Sept 1996 5" This file may be free distributed so long as these credits remain unchanged. 6" 7" Modified by Bram Moolenaar ([email protected]), 1996 Sept 10 8" - Made it quite a bit faster, but now needs search patterns in the text 9" - Changed the order of mappings to top-down. 10" - Made "g" run the whole thing, "C" run one generation. 11" - Added support for any uppercase character instead of 'X' 12" 13" Rules: 14" If a germ has 0 or 1 live neighbors it dies of loneliness 15" If a germ has 2 or 3 live neighbors it survives 16" If a germ has 4 to 8 live neighbors it dies of starvation 17" If an empty box has 3 live neighbors a new germ is born 18" 19" A new born germ is an "A". Every generation it gets older: B, C, etc. 20" A germ dies of old age when it reaches "Z". 21" 22" Notice the rules do not mention edges. This version has the edges wrap 23" around. I have an earlier version that offers the option of live edges or 24" dead edges. Email me if you are interested. -Eli- 25" 26" Note: This is slow! One generation may take up to ten minutes (depends on 27" your computer and the vi version). 28" 29" Quite a lot of the messy stuff is to work around the vi error "Can't yank 30" inside global/macro". Still doesn't work for all versions of vi. 31" 32" To use these macros: 33" 34" vi start vi/vim 35" 36" :so life.mac Source this file 37" 38" g 'g'o! runs everything until interrupted: "IR". 39" 40" I Initialize everything. A board will be drawn at the end 41" of the current buffer. All line references in these macros 42" are relative to the end of the file and playing the game 43" can be done safely with any file as the current buffer. 44" 45" Change the left field with spaces and uppercase letters to suit 46" your taste. 47" 48" C 'C'ompute one generation. 49" + idem, time running one generation. 50" R 'R'un 'C'ompute until interrupted. 51" i<nr><Esc>z Make a number the only thing on the current line and use 52" 'z' to time that many generations. 53" 54" Time to run 30 generations on my 233 AMD K6 (FreeBSD 3.0): 55" vim 5.4 xterm 51 sec 56" gvim 5.4 Athena 42 sec 57" gvim 5.4 Motif 42 sec 58" gvim 5.4 GTK 50 sec 59" nvi 1.79 xterm 58 sec 60" vi 3.7 xterm 2 min 30 sec 61" Elvis 2.1 xterm 7 min 50 sec 62" Elvis 2.1 X11 6 min 31 sec 63" 64" Time to run 30 generations on my 850 AMD Duron (FreeBSD 4.2): 65" vim 5.8 xterm 21 sec 66" vim 6.0 xterm 24 sec 67" vim 6.0 Motif 32 sec 68" nvi 1.79 xterm 29 sec 69" vi 3.7 xterm 32 sec 70" elvis 2.1.4 xterm 34 sec 71" 72" And now the macros, more or less in top-down order. 73" 74" ----- macros that can be used by the human ----- 75" 76" 'g'o: 'I'nitialize and then 'R'un 'C'ompute recursively (used by the human) 77map g IR 78" 79" 80" 'R'un 'C'ompute recursively (used by the human and 'g'o) 81map R CV 82" work around "tail recursion" problem in vi, "V" == "R". 83map V R 84" 85" 86" 'I'nitialize the board (used by the human and 'g'o) 87map I G)0)0)0)0)1)0)0)2)0)0)0)0,ok,-11k,-,R,IIN 88" 89" 90" 'C'ompute next generation (used by the human and others) 91map C T>>>>>>>>B& 92" 93" 94" Time running one generation (used by the human) 95map + <1C<2 96" 97" 98" Time running N generations, where N is the number on the current line. 99" (used by the human) 100map z ,^,&,*,&<1,*<2 101" 102" ----- END of macros that can be used by the human ----- 103" 104" ----- Initialisation ----- 105" 106map ,- :s/./-/g 107map ,o oPut 'X's in the left box, then hit 'C' or 'R' 108map ,R 03stop 109" 110" Write a new line (used by 'I'nitialize board) 111" In remembrance of John Conway, 26 December 1937 – 11 April 2020. 112map )0 o- --....................--....................- 113map )1 o- JOHN CONWAY --....................--....................- 114map )2 o- LIVES --....................--....................- 115" 116" 117" Initialisation of the pattern/command to execute for working out a square. 118" Pattern is: "#<germ><count>" 119" where <germ> is " " if the current germ is dead, "X" when living. 120" <count> is the number of living neighbours (including current germ) 121" expressed in X's 122" 123map ,Il8 O#XXXXXXXXXX .`a22lr 124map ,Id8 o# XXXXXXXX .`a22lr 125map ,Il7 o#XXXXXXXXX .`a22lr 126map ,Id7 o# XXXXXXX .`a22lr 127map ,Il6 o#XXXXXXXX .`a22lr 128map ,Id6 o# XXXXXX .`a22lr 129map ,Il5 o#XXXXXXX .`a22lr 130map ,Id5 o# XXXXX .`a22lr 131map ,Il4 o#XXXXXX .`a22lr 132map ,Id4 o# XXXX .`a22lr 133map ,Il3 o#XXXXX .,a 134map ,Id3 o# XXX .`a22lrA 135map ,Il2 o#XXXX .,a 136map ,Id2 o# XX .`a22lr 137map ,Il1 o#XXX .`a22lr 138map ,Id1 o# X .`a22lr 139map ,Il0 o#XX .`a22lr 140map ,Id0 o# .`a22lr 141" 142" Patterns used to replace a germ with its next generation 143map ,Iaa o=AB =BC =CD =DE =EF =FG =GH =HI =IJ =JK =KL =LM =MN =NO =OP =PQ =QR 144map ,Iab o=RS =ST =TU =UV =VW =WX =XY =YZ =Z 145" 146" Insert the searched patterns above the board 147map ,IIN G?^top 148,Il8,Id8,Il7,Id7,Il6,Id6,Il5,Id5,Il4,Id4,Il3,Id3,Il2,Id2,Il1,Id1,Il0,Id0,Iaa,Iab 149" 150" ----- END of Initialisation ----- 151" 152" ----- Work out one line ----- 153" 154" Work out 'T'op line (used by show next) 155map T G,c2k,!9k,@,#j>2k,$j 156" 157" Work out 'B'ottom line (used by show next) 158map B ,%k>,$ 159" 160" Work out a line (used by show next, work out top and bottom lines) 161map > 0 LWWWWWWWWWWWWWWWWWW,rj 162" 163" Refresh board (used by show next) 164map & :%s/^\(-[ A-Z]*-\)\(-[ A-Z]*-\)\(-[.]*-\)$/\2\3\3/ 165" 166" 167" Work around vi multiple yank/put in a single macro limitation 168" (used by work out top and/or bottom line) 169map ,$ dd 170map ,% "cp 171map ,! "byy 172map ,@ "cyy 173map ,# "bP 174map ,c c$ 175" 176" ----- END of Work out one line ----- 177" 178" ----- Work out one square ----- 179" 180" The next three work out a square: put all nine chars around the current 181" character on the bottom line (the bottom line must be empty when starting). 182" 183" 'W'ork out a center square (used by work out line) 184map W makh,3`ah,3`ajh,3( 185" 186" 187" Work out a 'L'eft square (used by work out line) 188map L makf-h,1`ak,2`af-h,1`a,2`ajf-h,1`aj,2( 189" 190" 191" Work out a 'R'ight square (used by work out line) 192map ,r makh,2`akF-l,1`ah,2`aF-l,1`ajh,2`ajF-l,1( 193" 194" 'M'ove a character to the end of the file (used by all work out square 195" macros) 196" 197map ,1 y G$p 198map ,2 2y G$p 199map ,3 3y G$p 200" 201" 202" ----- END of Work out one square ----- 203" 204" ----- Work out one germ ----- 205" 206" Generate an edit command that depends on the number of living in the last 207" line, and then run the edit command. (used by work out square). 208" Leaves the cursor on the next character to be processed. 209" 210map ( ,s,i,X0i?^#A 2110,df.l,Y21h 212" 213" Delete 's'paces (deads); 214" The number of remaining characters is the number of living neighbours. 215map ,s :.g/ /s///g 216" 217" Insert current character in the last line 218map ,i `ay GP 219" 220" Replace any uppercase letter with 'X'; 221map ,X :.g/[A-Z]/s//X/g 222" 223" Delete and execute the rest of the line 224map ,d "qd$@q 225" 226" Yank and execute the rest of the line 227map ,Y "qy$@q 228" 229" Yank the character under the cursor 230map ,j y 231" 232" Put the current cut buffer after the cursor 233map ,m p 234" 235" Delete the character under the cursor 236map ,n x 237" 238" Replace a character by its next, A --> B, B --> C, etc. 239map ,a `a,jGi?=,ma 2400,dll,j`a21l,ml,nh 241" 242" ----- END of Work out one germ ----- 243" 244" ----- timing macros ----- 245" 246" Get current date (used by time a generation) 247map << :r!date 248map <1 G?^top 249O<< 250map <2 G?^top 251k<< 252" 253" 254" Turn number on current line into edit command (used by time N generations) 255map ,^ AiC 256" 257" 258" Delete current line and save current line (used by time N generations) 259map ,& 0"gd$ 260" 261" 262" Run saved line (used by time N generations) 263map ,* @g 264" 265" ----- END of timing macros ----- 266" 267" End of the macros. 268