Initial import of Hunter version 1.0 revision 2002.0126 sources.
Cat's Eye Technologies
12 years ago
0 | <html><head> | |
1 | <meta http-equiv="Content-Type" content="text/html;CHARSET=iso-8859-1"> | |
2 | <title>Cat's Eye Technologies: The HUNTER Programming Language</title> | |
3 | </head> | |
4 | <body> | |
5 | ||
6 | <h1>HUNTER</h1> | |
7 | ||
8 | <p><font size=-1> <img src="/images/icons/copyright.gif" | |
9 | align=absmiddle width=12 height=12 alt="(c)" border=0>2002-2004 <a href="/">Cat's Eye Technologies</a>. All rights reserved.<br> | |
10 | This software is OSI Certified Open Source Software.<br> | |
11 | OSI Certified is a certification mark of the <a href="http://www.opensource.org/"><img | |
12 | src="/images/icons/webicon.gif" alt="[WWW]" border=0 width=12 height=12>Open Source Initiative</a>.<br> | |
13 | See the file <a href="license.txt">license.txt</a> for license information.</font> | |
14 | ||
15 | <h3>Introduction</h3> | |
16 | ||
17 | <p>To quote <a href="hunter.txt">hunter.txt</a>: | |
18 | ||
19 | <blockquote> | |
20 | <p>"It is perceived that one of the biggest problems in maintaining | |
21 | interest in programming is the above linear growth of boredom | |
22 | compared to the usefulness of the program, resulting in an | |
23 | acute loss of enthusiasm on the part of the programmers and | |
24 | ultimately the abandonment of the software.</p> | |
25 | ||
26 | <p>"This document intends to address that by introducing a language | |
27 | with new models for sharing, flow control, and data manipulation, | |
28 | which make all dependencies in a program globally accessible and | |
29 | radically oblique at the language level.</p> | |
30 | ||
31 | <p>"We introduce the language, which is a deterministic particle | |
32 | automaton based on mazespace-rewriting and critter-style message | |
33 | passing and, being ASCII art, is inherently graphical in notation..."</p> | |
34 | </blockquote> | |
35 | ||
36 | <h3>Implementation</h3> | |
37 | ||
38 | <p>The Perl 5 implementation of HUNTER requires the | |
39 | <a href="/projects/virtcons/">_Console::Virtual | |
40 | module</a>.</p> | |
41 | ||
42 | </body></html> |
0 | Concurrent Maze Space Transformation | |
1 | (with Authentic Interrodent Communication) | |
2 | In The HUNTER Programming Language | |
3 | ||
4 | ||
5 | It is perceived that one of the biggest problems in maintaining | |
6 | interest in programming is the above linear growth of boredom | |
7 | compared to the usefulness of the program, resulting in an | |
8 | acute loss of enthusiasm on the part of the programmers and | |
9 | ultimately the abandonment of the software. | |
10 | ||
11 | This document intends to address that by introducing a language | |
12 | with new models for sharing, flow control, and data manipulation, | |
13 | which make all dependencies in a program globally accessible and | |
14 | radically oblique at the language level. | |
15 | ||
16 | We introduce the language, which is a deterministic particle | |
17 | automaton based on mazespace-rewriting and critter-style message | |
18 | passing and, being ASCII art, is inherently graphical in notation... | |
19 | ||
20 | ||
21 | The HUNTER Programming Language | |
22 | (c)2000-2002 Cat's Eye Technologies. All rights reserved. | |
23 | ||
24 | Each HUNTER program consists of a two-dimensional Cartesian-grid | |
25 | playfield of any reasonable arbitrary size. Each square in this | |
26 | grid is called a cell. Each cell may contain one of several | |
27 | things, or be considered 'empty'. It may also contain a mouse, | |
28 | which is a particularly special kind of thing. However, a mouse | |
29 | must start in an otherwise empty square. | |
30 | ||
31 | Mice are particularly special because they have agency. Unlike | |
32 | walls and pieces of cheese, they do things. Primarily, they move | |
33 | around. They do so at runtime. | |
34 | ||
35 | The deterministic fashion a mouse moves around - always checking | |
36 | east, then north, then west, then south, in each cell - and its | |
37 | memory (each mouse keeps a 'map' of where it's been in it's head | |
38 | and tries not to backtrack unless there is nowhere else new to | |
39 | go) ensures that, given some time, and all other things being | |
40 | equal, a mouse will traverse it's entire environment and will | |
41 | return to where it started. The process then repeats, holding | |
42 | the mouse in a state of perpetual live lock. | |
43 | ||
44 | However, not all other things may be equal. Indeed, the mouse | |
45 | may nibble on a bit of strychnine and die. Or, other mice may | |
46 | be concurrently tranversing the same maze, and two mice may not | |
47 | share the same space, so they may block each other's progress. | |
48 | ||
49 | Mice may not move through walls but they may move through empty | |
50 | space and on top of items found in the playfield, possibly | |
51 | altering them (see below.) | |
52 | ||
53 | Execution ends when all mice are dead. | |
54 | ||
55 | An example HUNTER program might be: | |
56 | ||
57 | ######## | |
58 | # 1#2# | |
59 | # #### # | |
60 | # # | |
61 | # ###### | |
62 | # m# | |
63 | #+###### | |
64 | # !# | |
65 | ######## | |
66 | ||
67 | where | |
68 | ||
69 | # indicates a wall | |
70 | m indicates a mouse | |
71 | the digits 0 to 9 represent types of cheese | |
72 | 0 = cheddar | |
73 | 1 = american | |
74 | 2 = swiss | |
75 | 3 = gouda | |
76 | 4 = mozzarella | |
77 | 5 = farmer | |
78 | 6 = blue | |
79 | 7 = gorgonzola | |
80 | 8 = feta | |
81 | 9 = bat's-milk | |
82 | ! indicates a bit of strychnine | |
83 | + indicates a pinwheel | |
84 | . indicates a mouse turd | |
85 | w indicates a dead mouse carcass | |
86 | ||
87 | other characters indicate other miscellaneous objects | |
88 | apropos to being in a maze, with undefined semantics, | |
89 | so they should be considered reserved | |
90 | ||
91 | Intermouse communication is done by mouse droppings. A mouse | |
92 | can leave a message to some other mouse by creating a mouse | |
93 | dropping where it currently is (assuming it has previously | |
94 | eaten a piece of cheese.) Other mice can detect mouse | |
95 | droppings and change their behaviour based on them. | |
96 | ||
97 | How mice create droppings is defined by how each mouse is | |
98 | trained. These mice are somewhat magical in that they can | |
99 | be trained to perform physically improbable tasks, such as | |
100 | turning one kind of cheese into another. | |
101 | ||
102 | Mice are trained globally by the mazespace-rewriting | |
103 | rules. These are the guidelines by which rodents live their | |
104 | lives. Each rule must be on a line by itself and has the | |
105 | following form: | |
106 | ||
107 | *things>droppings | |
108 | ||
109 | For example, | |
110 | ||
111 | *12>21 | |
112 | ||
113 | Then, when a mouse encounters a piece of American cheese, | |
114 | followed by a piece of Swiss cheese, it will eat them and | |
115 | excrete a bit of Swiss cheese followed by a bit of American | |
116 | cheese. This is just an example. | |
117 | ||
118 | Mice will eat cheese but will not eat mouse droppings, | |
119 | pinwheels, or other inedible items. | |
120 | ||
121 | Specifying strychnine, walls, or mice on the left-hand side | |
122 | of a rewriting rule is not guaranteed to be able to produce | |
123 | a match. The behaviour of specifing mice on the right-hand | |
124 | side of a rewriting rule is undefined. | |
125 | ||
126 | ||
127 | ||
128 | Chris Pressey | |
129 | Winnipeg, Manitoba, Canada | |
130 | Original Oct 24 2000 | |
131 | Revised for clarity Jan 26 2002 |
0 | Copyright (c)2001, Cat's Eye Technologies. | |
1 | All rights reserved. | |
2 | ||
3 | Redistribution and use in source and binary forms, with or without | |
4 | modification, are permitted provided that the following conditions | |
5 | are met: | |
6 | ||
7 | Redistributions of source code must retain the above copyright | |
8 | notice, this list of conditions and the following disclaimer. | |
9 | ||
10 | Redistributions in binary form must reproduce the above copyright | |
11 | notice, this list of conditions and the following disclaimer in | |
12 | the documentation and/or other materials provided with the | |
13 | distribution. | |
14 | ||
15 | Neither the name of Cat's Eye Technologies nor the names of its | |
16 | contributors may be used to endorse or promote products derived | |
17 | from this software without specific prior written permission. | |
18 | ||
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | |
20 | CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
21 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
22 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
23 | DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE | |
24 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | |
25 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
27 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | POSSIBILITY OF SUCH DAMAGE. |
0 | #################################### | |
1 | ##1 #1 #0 #1 #0 #0 #1 #13m#!# | |
2 | # 0# 0# 1# 1# 0# 1# 1# 0### # | |
3 | # ################################ # | |
4 | # # | |
5 | #################################### | |
6 | *3>+0 | |
7 | *00>0 0 | |
8 | *01>1 0 | |
9 | *10>1 0 | |
10 | *11>0 1 | |
11 | ||
12 |
0 | ######################### | |
1 | #M # M # M#M # M # M# | |
2 | # # # # # # # | |
3 | # # # # # # # | |
4 | ############# # # # | |
5 | # # # # # # # | |
6 | #M # M # M# # # # | |
7 | # # # # # # # | |
8 | ############# # # # | |
9 | #M # #M # # # # | |
10 | # # M # # ! # ! # ! # | |
11 | # M# # M# # # # | |
12 | ############# # # # | |
13 | # # # # # # # | |
14 | #M # M # M# # # # | |
15 | # # # # # # # | |
16 | ############# # # # | |
17 | # # # # # # # | |
18 | # # # # # # # | |
19 | #M # M # M#M # M # M# | |
20 | ######################### |
0 | ################## | |
1 | # 1#2# # | |
2 | # #### # # | |
3 | # # # | |
4 | # ###### M # | |
5 | # M# # | |
6 | #+###### # | |
7 | # !# # | |
8 | ################## | |
9 | *12+>3 | |
10 | *21+>3 |
0 | ####################### | |
1 | #m 1111111111111 # | |
2 | ####################### | |
3 | ||
4 | ####################### | |
5 | #m ............. # | |
6 | ####################### | |
7 | ||
8 | *11>22 | |
9 | *22>11 | |
10 | *..>:: | |
11 | *::>.. |
0 | #################### | |
1 | #2#1+1#0+1#0+0#1+1## | |
2 | #!+0#0+1#1+0#1+1#0m# | |
3 | #################### | |
4 | *00+>0 | |
5 | *01+>1 | |
6 | *10+>1 | |
7 | *11+>0 | |
8 | ||
9 |
0 | #!/usr/bin/perl | |
1 | ||
2 | # HUNTER - concurrent maze-space traversal language | |
3 | # v2002.01.26 Chris Pressey, Cat's Eye Technologies | |
4 | ||
5 | # Copyright (c)2002, Cat's Eye Technologies. | |
6 | # All rights reserved. | |
7 | # | |
8 | # Redistribution and use in source and binary forms, with or without | |
9 | # modification, are permitted provided that the following conditions | |
10 | # are met: | |
11 | # | |
12 | # Redistributions of source code must retain the above copyright | |
13 | # notice, this list of conditions and the following disclaimer. | |
14 | # | |
15 | # Redistributions in binary form must reproduce the above copyright | |
16 | # notice, this list of conditions and the following disclaimer in | |
17 | # the documentation and/or other materials provided with the | |
18 | # distribution. | |
19 | # | |
20 | # Neither the name of Cat's Eye Technologies nor the names of its | |
21 | # contributors may be used to endorse or promote products derived | |
22 | # from this software without specific prior written permission. | |
23 | # | |
24 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | |
25 | # CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
26 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
27 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
28 | # DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE | |
29 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | |
30 | # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
31 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
32 | # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
33 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
34 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
35 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
36 | # POSSIBILITY OF SUCH DAMAGE. | |
37 | ||
38 | # usage: [perl] hunter[.pl] [-no-eat] [-delay xxx] hunter-playfield-file | |
39 | # requirements: Curses, or ANSI terminal, or Win32 Console. | |
40 | ||
41 | # history: v2000.08.05 - started prototyping (from worb.pl). | |
42 | # v2000.08.07 - added deterministic traversal. | |
43 | # mouse always tries: E, N, W, S. | |
44 | # v2000.10.24 - cleaned up code, added rewriting. | |
45 | # v2000.12.08 - added support for virtual console. | |
46 | # v2000.12.15 - refined support for virtual console. | |
47 | # v2001.01.24 - adapted to new virtual console modules. | |
48 | # v2002.01.26 - fixed behaviour of eating of cheese | |
49 | # added command line options | |
50 | # does not rely on "\n" in screen driver | |
51 | ||
52 | # Uncomment this line to use a specific display driver. | |
53 | # BEGIN { $_Console::Virtual::setup{display} = 'ANSI'; } | |
54 | ||
55 | use _Console::Virtual 2001.0123 | |
56 | qw(getkey display gotoxy clrscr clreol | |
57 | normal inverse bold update_display); | |
58 | ||
59 | ### GLOBALS ### | |
60 | ||
61 | @mouse = (); | |
62 | @playfield = (); | |
63 | @mouse_at_cache = (); | |
64 | @rule = (); | |
65 | ||
66 | $x = 0; $y = 0; | |
67 | $no_eat = 0; # compatibility flag | |
68 | $delay = 300; | |
69 | ||
70 | ### SUBS ### | |
71 | ||
72 | sub draw_playfield | |
73 | { | |
74 | gotoxy(1,1); | |
75 | my $i; my $j; my $p; | |
76 | for($j = 0; $j <= $maxy; $j++) | |
77 | { | |
78 | for($i = 0; $i <= $maxx; $i++) | |
79 | { | |
80 | if (is_mouse_at($i,$j)) | |
81 | { | |
82 | display('m'); | |
83 | } else | |
84 | { | |
85 | display($playfield[$i][$j]); | |
86 | } | |
87 | } | |
88 | gotoxy(1, $j+2); | |
89 | } | |
90 | } | |
91 | ||
92 | sub is_mouse_at | |
93 | { | |
94 | my $x = shift; my $y = shift; | |
95 | return $mouse_at_cache[$x][$y] || 0; | |
96 | } | |
97 | ||
98 | sub vacant | |
99 | { | |
100 | my $x = shift; my $y = shift; | |
101 | return 0 if $playfield[$x][$y] eq '#'; | |
102 | return 0 if is_mouse_at($x,$y); | |
103 | return 1; | |
104 | } | |
105 | ||
106 | ### MAIN ### | |
107 | ||
108 | while ($ARGV[0] =~ /^\-\-?(.*?)$/) | |
109 | { | |
110 | my $opt = $1; | |
111 | shift @ARGV; | |
112 | if ($opt eq 'no-eat') | |
113 | { | |
114 | $no_eat = 1; | |
115 | } | |
116 | elsif ($opt eq 'delay') | |
117 | { | |
118 | $delay = 0+shift @ARGV; | |
119 | } | |
120 | else | |
121 | { | |
122 | die "Unknown command-line option --$opt"; | |
123 | } | |
124 | } | |
125 | ||
126 | open PLAYFIELD, $ARGV[0]; | |
127 | while(defined($line = <PLAYFIELD>)) | |
128 | { | |
129 | my $i; | |
130 | chomp($line); | |
131 | if ($line =~ /^\*(.*?)\>(.*?)$/) | |
132 | { | |
133 | push @rule, [$1, $2]; | |
134 | } else | |
135 | { | |
136 | for($i = 0; $i < length($line); $i++) | |
137 | { | |
138 | my $c = substr($line, $i, 1); | |
139 | if (ucfirst($c) eq 'M') | |
140 | { | |
141 | $c = ' '; | |
142 | push @mouse, | |
143 | { | |
144 | 'x' => $x, | |
145 | 'y' => $y, | |
146 | 'been' => [[]], | |
147 | 'seen' => '', | |
148 | 'stack' => [ 1 ], | |
149 | 'dead' => 0, | |
150 | 'out' => '', | |
151 | }; | |
152 | $mouse_at_cache[$x][$y] = 1; | |
153 | } | |
154 | $playfield[$x][$y] = $c; | |
155 | $x++; if ($x > $maxx) { $maxx = $x; } | |
156 | } | |
157 | $x = 0; | |
158 | $y++; if ($y > $maxy) { $maxy = $y; } | |
159 | } | |
160 | } | |
161 | close PLAYFIELD; | |
162 | ||
163 | clrscr(); | |
164 | ||
165 | draw_playfield(); | |
166 | ||
167 | $start_time = time(); | |
168 | $tick = 1; | |
169 | while(1) | |
170 | { | |
171 | my $mouse; | |
172 | my $pole; | |
173 | my $deadmice = 0; # first time I've ever used THAT as a variable name! ;-) | |
174 | foreach $mouse (@mouse) | |
175 | { | |
176 | ResetMouse: | |
177 | ||
178 | if ($mouse->{dead}) | |
179 | { | |
180 | $deadmice++; | |
181 | next; | |
182 | } | |
183 | ||
184 | my $tos = $mouse->{stack}[$#{$mouse->{stack}}]; | |
185 | my $new_x = 0; my $new_y = 0; | |
186 | ||
187 | if ($tos < 5) | |
188 | { | |
189 | if ($tos == 1) | |
190 | { | |
191 | $new_x = $mouse->{x} + 1; | |
192 | $new_y = $mouse->{y}; | |
193 | } | |
194 | elsif ($tos == 2) | |
195 | { | |
196 | $new_x = $mouse->{x}; | |
197 | $new_y = $mouse->{y} - 1; | |
198 | } | |
199 | elsif ($tos == 3) | |
200 | { | |
201 | $new_x = $mouse->{x} - 1; | |
202 | $new_y = $mouse->{y}; | |
203 | } | |
204 | elsif ($tos == 4) | |
205 | { | |
206 | $new_x = $mouse->{x}; | |
207 | $new_y = $mouse->{y} + 1; | |
208 | } else | |
209 | { | |
210 | die "Can't be!"; | |
211 | } | |
212 | ||
213 | if((defined($mouse->{been}[$new_x][$new_y]) and $mouse->{been}[$new_x][$new_y]) | |
214 | or not vacant($new_x, $new_y)) | |
215 | { | |
216 | $mouse->{stack}[$#{$mouse->{stack}}]++; | |
217 | next; | |
218 | } | |
219 | ||
220 | push @{$mouse->{stack}}, 1; | |
221 | $mouse->{been}[$mouse->{x}][$mouse->{y}] = 1; | |
222 | } | |
223 | else | |
224 | { | |
225 | $tos = pop @{$mouse->{stack}}; | |
226 | if ($#{$mouse->{stack}} == -1) | |
227 | { | |
228 | $mouse->{been} = [[]]; | |
229 | push @{$mouse->{stack}}, 1; | |
230 | goto ResetMouse; | |
231 | } | |
232 | $tos = $mouse->{stack}[$#{$mouse->{stack}}]; | |
233 | $mouse->{been}[$mouse->{x}][$mouse->{y}] = 0; | |
234 | if ($tos == 1) | |
235 | { | |
236 | $new_x = $mouse->{x} - 1; | |
237 | $new_y = $mouse->{y}; | |
238 | } | |
239 | elsif ($tos == 2) | |
240 | { | |
241 | $new_x = $mouse->{x}; | |
242 | $new_y = $mouse->{y} + 1; | |
243 | } | |
244 | elsif ($tos == 3) | |
245 | { | |
246 | $new_x = $mouse->{x} + 1; | |
247 | $new_y = $mouse->{y}; | |
248 | } | |
249 | elsif ($tos == 4) | |
250 | { | |
251 | $new_x = $mouse->{x}; | |
252 | $new_y = $mouse->{y} - 1; | |
253 | } | |
254 | $mouse->{stack}[$#{$mouse->{stack}}]++; | |
255 | if (not vacant($new_x, $new_y)) | |
256 | { | |
257 | next; | |
258 | } | |
259 | } | |
260 | ||
261 | if ($mouse->{out} =~ /^(.)/) | |
262 | { | |
263 | $playfield[$mouse->{x}][$mouse->{y}] = $1; | |
264 | $mouse->{out} = $'; | |
265 | } | |
266 | ||
267 | gotoxy($mouse->{x}+1, $mouse->{y}+1); | |
268 | display($playfield[$mouse->{x}][$mouse->{y}]); | |
269 | $mouse_at_cache[$mouse->{x}][$mouse->{y}] = 0; | |
270 | $mouse->{x} = $new_x; | |
271 | $mouse->{y} = $new_y; | |
272 | $mouse_at_cache[$mouse->{x}][$mouse->{y}] = 1; | |
273 | gotoxy($mouse->{x}+1, $mouse->{y}+1); | |
274 | display('m'); | |
275 | ||
276 | my $item = $playfield[$mouse->{x}][$mouse->{y}]; | |
277 | if ($item eq '!') | |
278 | { | |
279 | $mouse->{dead} = 1; | |
280 | $playfield[$mouse->{x}][$mouse->{y}] = 'w'; # mouse carcass | |
281 | gotoxy($mouse->{x}+1, $mouse->{y}+1); | |
282 | display($playfield[$mouse->{x}][$mouse->{y}]); | |
283 | } | |
284 | elsif ($item ne ' ') | |
285 | { | |
286 | $mouse->{seen} .= $item; | |
287 | if ($item =~ /^\d$/) | |
288 | { | |
289 | $playfield[$mouse->{x}][$mouse->{y}] = ' ' unless $no_eat; | |
290 | } | |
291 | } | |
292 | ||
293 | my $r; my $dr = 0; | |
294 | while (not $dr) | |
295 | { | |
296 | $dr = 1; | |
297 | foreach $r (@rule) | |
298 | { | |
299 | my $q = quotemeta($r->[0]); | |
300 | if ($mouse->{seen} =~ /$q$/) | |
301 | { | |
302 | $mouse->{seen} = $`; | |
303 | $mouse->{out} .= $r->[1]; | |
304 | $dr = 0; | |
305 | } | |
306 | } | |
307 | } | |
308 | } | |
309 | if ($deadmice == $#mouse+1) | |
310 | { | |
311 | exit(0); | |
312 | } | |
313 | update_display(); | |
314 | for($i = 1; $i < $delay; $i++) | |
315 | { | |
316 | gotoxy(1,20); | |
317 | } | |
318 | } | |
319 | ||
320 | ### END of hunter.pl ### |