7
|
1 " Macros to play Conway's Game of Life in vi
|
|
2 " Version 1.0m: edges wrap
|
1618
|
3 " by Eli-the-Bearded Benjamin Elijah Griffin <vim@eli.users.panix.com>
|
|
4 " Sept 1996
|
7
|
5 " This file may be free distributed so long as these credits remain unchanged.
|
|
6 "
|
|
7 " Modified by Bram Moolenaar (Bram@vim.org), 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)
|
|
77 map g IR
|
|
78 "
|
|
79 "
|
|
80 " 'R'un 'C'ompute recursively (used by the human and 'g'o)
|
|
81 map R CV
|
|
82 " work around "tail recursion" problem in vi, "V" == "R".
|
|
83 map V R
|
|
84 "
|
|
85 "
|
|
86 " 'I'nitialize the board (used by the human and 'g'o)
|
|
87 map 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)
|
|
91 map C T>>>>>>>>B&
|
|
92 "
|
|
93 "
|
|
94 " Time running one generation (used by the human)
|
|
95 map + <1C<2
|
|
96 "
|
|
97 "
|
|
98 " Time running N generations, where N is the number on the current line.
|
|
99 " (used by the human)
|
|
100 map z ,^,&,*,&<1,*<2
|
|
101 "
|
|
102 " ----- END of macros that can be used by the human -----
|
|
103 "
|
|
104 " ----- Initialisation -----
|
|
105 "
|
|
106 map ,- :s/./-/g
|
|
107 map ,o oPut 'X's in the left box, then hit 'C' or 'R'
|
|
108 map ,R 03stop
|
|
109 "
|
|
110 " Write a new line (used by 'I'nitialize board)
|
20115
|
111 " In remembrance of John Conway, 26 December 1937 – 11 April 2020.
|
7
|
112 map )0 o- --....................--....................-
|
20115
|
113 map )1 o- JOHN CONWAY --....................--....................-
|
7
|
114 map )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 "
|
|
123 map ,Il8 O#XXXXXXXXXX .`a22lr
|
|
124 map ,Id8 o# XXXXXXXX .`a22lr
|
|
125 map ,Il7 o#XXXXXXXXX .`a22lr
|
|
126 map ,Id7 o# XXXXXXX .`a22lr
|
|
127 map ,Il6 o#XXXXXXXX .`a22lr
|
|
128 map ,Id6 o# XXXXXX .`a22lr
|
|
129 map ,Il5 o#XXXXXXX .`a22lr
|
|
130 map ,Id5 o# XXXXX .`a22lr
|
|
131 map ,Il4 o#XXXXXX .`a22lr
|
|
132 map ,Id4 o# XXXX .`a22lr
|
|
133 map ,Il3 o#XXXXX .,a
|
|
134 map ,Id3 o# XXX .`a22lrA
|
|
135 map ,Il2 o#XXXX .,a
|
|
136 map ,Id2 o# XX .`a22lr
|
|
137 map ,Il1 o#XXX .`a22lr
|
|
138 map ,Id1 o# X .`a22lr
|
|
139 map ,Il0 o#XX .`a22lr
|
|
140 map ,Id0 o# .`a22lr
|
|
141 "
|
14999
|
142 " Patterns used to replace a germ with its next generation
|
7
|
143 map ,Iaa o=AB =BC =CD =DE =EF =FG =GH =HI =IJ =JK =KL =LM =MN =NO =OP =PQ =QR
|
|
144 map ,Iab o=RS =ST =TU =UV =VW =WX =XY =YZ =Z
|
|
145 "
|
|
146 " Insert the searched patterns above the board
|
|
147 map ,IIN G?^top
,Il8,Id8,Il7,Id7,Il6,Id6,Il5,Id5,Il4,Id4,Il3,Id3,Il2,Id2,Il1,Id1,Il0,Id0,Iaa,Iab
|
|
148 "
|
|
149 " ----- END of Initialisation -----
|
|
150 "
|
|
151 " ----- Work out one line -----
|
|
152 "
|
|
153 " Work out 'T'op line (used by show next)
|
|
154 map T G,c2k,!9k,@,#j>2k,$j
|
|
155 "
|
|
156 " Work out 'B'ottom line (used by show next)
|
|
157 map B ,%k>,$
|
|
158 "
|
|
159 " Work out a line (used by show next, work out top and bottom lines)
|
|
160 map > 0 LWWWWWWWWWWWWWWWWWW,rj
|
|
161 "
|
|
162 " Refresh board (used by show next)
|
|
163 map & :%s/^\(-[ A-Z]*-\)\(-[ A-Z]*-\)\(-[.]*-\)$/\2\3\3/
|
|
164 "
|
|
165 "
|
|
166 " Work around vi multiple yank/put in a single macro limitation
|
|
167 " (used by work out top and/or bottom line)
|
|
168 map ,$ dd
|
|
169 map ,% "cp
|
|
170 map ,! "byy
|
|
171 map ,@ "cyy
|
|
172 map ,# "bP
|
|
173 map ,c c$
|
|
174 "
|
|
175 " ----- END of Work out one line -----
|
|
176 "
|
|
177 " ----- Work out one square -----
|
|
178 "
|
|
179 " The next three work out a square: put all nine chars around the current
|
|
180 " character on the bottom line (the bottom line must be empty when starting).
|
|
181 "
|
|
182 " 'W'ork out a center square (used by work out line)
|
|
183 map W makh,3`ah,3`ajh,3(
|
|
184 "
|
|
185 "
|
|
186 " Work out a 'L'eft square (used by work out line)
|
|
187 map L makf-h,1`ak,2`af-h,1`a,2`ajf-h,1`aj,2(
|
|
188 "
|
|
189 "
|
|
190 " Work out a 'R'ight square (used by work out line)
|
|
191 map ,r makh,2`akF-l,1`ah,2`aF-l,1`ajh,2`ajF-l,1(
|
|
192 "
|
|
193 " 'M'ove a character to the end of the file (used by all work out square
|
|
194 " macros)
|
|
195 "
|
|
196 map ,1 y G$p
|
|
197 map ,2 2y G$p
|
|
198 map ,3 3y G$p
|
|
199 "
|
|
200 "
|
|
201 " ----- END of Work out one square -----
|
|
202 "
|
|
203 " ----- Work out one germ -----
|
|
204 "
|
|
205 " Generate an edit command that depends on the number of living in the last
|
|
206 " line, and then run the edit command. (used by work out square).
|
|
207 " Leaves the cursor on the next character to be processed.
|
|
208 "
|
|
209 map ( ,s,i,X0i?^#A
0,df.l,Y21h
|
|
210 "
|
|
211 " Delete 's'paces (deads);
|
|
212 " The number of remaining characters is the number of living neighbours.
|
|
213 map ,s :.g/ /s///g
|
|
214 "
|
|
215 " Insert current character in the last line
|
|
216 map ,i `ay GP
|
|
217 "
|
|
218 " Replace any uppercase letter with 'X';
|
|
219 map ,X :.g/[A-Z]/s//X/g
|
|
220 "
|
|
221 " Delete and execute the rest of the line
|
|
222 map ,d "qd$@q
|
|
223 "
|
|
224 " Yank and execute the rest of the line
|
|
225 map ,Y "qy$@q
|
|
226 "
|
|
227 " Yank the character under the cursor
|
|
228 map ,j y
|
|
229 "
|
|
230 " Put the current cut buffer after the cursor
|
|
231 map ,m p
|
|
232 "
|
|
233 " Delete the character under the cursor
|
|
234 map ,n x
|
|
235 "
|
14999
|
236 " Replace a character by its next, A --> B, B --> C, etc.
|
7
|
237 map ,a `a,jGi?=,ma
0,dll,j`a21l,ml,nh
|
|
238 "
|
|
239 " ----- END of Work out one germ -----
|
|
240 "
|
|
241 " ----- timing macros -----
|
|
242 "
|
|
243 " Get current date (used by time a generation)
|
|
244 map << :r!date
|
|
245 map <1 G?^top
O<<
|
|
246 map <2 G?^top
k<<
|
|
247 "
|
|
248 "
|
|
249 " Turn number on current line into edit command (used by time N generations)
|
|
250 map ,^ AiC
|
|
251 "
|
|
252 "
|
|
253 " Delete current line and save current line (used by time N generations)
|
|
254 map ,& 0"gd$
|
|
255 "
|
|
256 "
|
|
257 " Run saved line (used by time N generations)
|
|
258 map ,* @g
|
|
259 "
|
|
260 " ----- END of timing macros -----
|
|
261 "
|
|
262 " End of the macros.
|