git @ Cat's Eye Technologies Wierd / rel_1_0_2004_0302
Initial import of Wierd distribution version 1.0 revision 2004.0302. Cat's Eye Technologies 12 years ago
28 changed file(s) with 2189 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 There are two versions of this program:
1 asciiadd.w: reads two characters, adds their ASCII values, and prints them out
2 add.w: like above, but treats 0 as origin, so 1+2 is 3 rather than c
3
4 Note that add.w uses the 0 in the top-left corner (which is operationally
5 equivalent to the star used elsewhere) for the origin. This character can be
6 changed to an arbitrary one, but 0 has been chosen because it gives the most
7 intuitive effect.
8
9 See cat.doc for general Wierd notes.
0 There are several versions of this program:
1 cat1.w: reads one character and write it out, no check for EOF
2 cat2.w: pumps input to output, no check for EOF (makes use of the fact that
3 "conditionals" without any stack just continue going, although it
4 would be more logical to terminate the program with an error message)
5 cat3.w: reads one character, and if it isn't EOF, dump it out again
6 cat4.w: pumps input to output until EOF is reached
7
8 Versions 3 and 4 implicitly assume that EOF is -1. Due to how hard it is to
9 change a Wierd program once it has been wired, I, with this very sentence,
10 define that Wierd programs will see EOF as -1, even on computers that normally
11 use a different method.
12
13 Versions 3 and 4 make use of the getput operator, which selects which
14 operatation to perform opposite from the specifications. Since neither I nor
15 anybody else (like the writer of hello.w) wishes to change our programs, I
16 recommend leaving the interpreter alone and changing the specifications. Also,
17 the angles work the opposite way (the first example in the specifications is
18 treated by the interpreter as 315 degrees). Again, I recommend changing the
19 specifications.
20
21 The only true use of conditionals is in the EOF test candle (or if you prefer,
22 dynamite) of versions 3 and 4, although fake ones appear in versions 2 and 4
23 with the top-of-stack known to be zero just to turn the execution around.
24
25 It is also interesting to note that the loop to continue reading after the
26 first character seems like a big change but takes barely any space (although it
27 does cheat by temporarily creating a new thread which soon dies out), while
28 testing for EOF seems like a small change (after all, only one out of 256 input
29 characters will be affected) but takes a very long wire, primarily because the
30 input character is needed twice - once to test for EOF, once to print it out -
31 and since there is no stack-duplication operator (not that there is any room
32 for it, though gap-sparking could be made to have a side effect) and so I must
33 simulate it by putting the character in (1,1) (those coordinates have been
34 chosen because they are the easiest to push on the stack), then getting it
35 twice.
36
37 In cat4.w, the doomed thread (the one which appears when, quite literally,
38 looping, and soon vanishes again) might stumble across this character, but
39 Wierd has been designed in such a way that this can, at the worst, kill the
40 thread off one cycle earlier. This proves that it is more robust than normal
41 languages. In fact, the ONLY error condition possible in Wierd is if the
42 lop-left character is a space (although, as stated above, errors SHOULD also
43 appear for insufficient stack), and therefore Wierd is useful to teach
44 beginning programmers without getting them frustated about pages full of error
45 messages. Now if you're talking about bugs that aren't caught by the language
46 but just have the wrong effect, THOSE are easy.
47
48 But although cat4.w is large, it's not a bad as hello.w. One starts
49 understanding why many programs use external data files. They not only
50 increases modifiability (for example, the program does not have to be changed
51 if you choose to use a different languange for the output), but also
52 significantly decrease program size.
53
54 This gap jumping is annoying. I never yet ran into any need for it (if there
55 is nothing around that the program can go to instead, why not just fill the gap
56 with stars?), but sometimes the interpreter tries to gap jump when I want it to
57 kill the thread (which forces me to make the program LARGER to add space so no
58 gap jump occurs, which is the opposite of what it was meant to do), and worse,
59 I cannot see how it chooses when and where to jump. I recommend that the whole
60 misfeature be removed. By the way, according the the manual, "programs beyond
61 a certain complexity might simply be impossible to write, and would at least be
62 extremely impractical". If they are impossible, gap jumping will not help (see
63 above question). If practicality is an issue, I should be programming C, not
64 Wierd.
65
66 A more severe problem is that check-for-zero is the only available conditional.
67 This means that if a program wants to check, for exameple, if the top of the
68 stack is less than zero, then all 32768 options must be scanned. Changing this
69 would imply having to change existing programs, but the problem is severe
70 enough that this is a necessary evil. The earlier, the better (before even
71 more programs use the outdated version).
72
73 Although I do not do so myself, it is possible to include in-program comments
74 by including text in the program, either as the wire (with underscores
75 replacing spaces) or at a nonreachable distance from the program.
76
77 Finally, Wierd programs (or rather wires) are a good example of what sould NOT
78 be made with a text editor or anything remotely similar to it. In fact, it
79 requires a special "wire editor" which can, as one of its basic operations,
80 stretch wires, taking any knotted wires along, and as another, cutting off
81 wires for later use and then place them again in a possibly rotated form. It
82 is also useful if it would draw the angles next to the turns. Sometime in the
83 future, when I have a lot of free time and feel excessively insane, I might try
84 it. Don't hold your breath, though.
0 This program prints sequential ASCII characters, starting with the character in
1 (1,1) and ending with the character in (2,2). Currently, it starts with 0 and
2 ends with 9, so it counts through all digits. A not-so-well-formatted table of
3 all printable ASCII characters may be obtained by starting with ! and ending
4 with ~. The former ascii.w (not by me) also tries to print non-printable
5 characters, and doesn't automatically stop (beep beep beep beep beep beep beep
6 beep beep beep beep beep beep ad nauseum), so my version is fully superior.
7 Space may not be used as endpoint (because the endpoints must be parsed as code
8 once), but it may appear as intermediate value.
9
10 The basic operation is:
11 0. Get the current character and place it on the stack.
12 1. Write the top-of-stack (the current character) to the terminal.
13 2. Get the current character, which was lost from the stack in step 1, again.
14 3. Get the termination character and place it on the stack.
15 4. Subtract the two values on the stack.
16 5. If the result of step 4 was zero (the last character has just been printed),
17 quit the program. Otherwise, continue to step 6.
18 6. The stack is, once again, empty, so push the current character.
19 7. Increment the top of stack by dancing "left, left, right, left, right,
20 right", where all turns are 45 degrees.
21 8. Put the top of stack in the current character position.
22 9. With the stack empty again, go back to step 0 and repeat the whole process.
23
24 The wire has many crossings, although all but one are harmless "bridges" which
25 do not change direction and just shrink the wire a bit by avoiding padding.
26
27 To do: write a newline when done (this is not as easy in Wierd as it sounds,
28 because a newline cannot be entered as starting element for a cell), ask the
29 user to enter the start and end characters (inputting and remembering is not
30 that hard, but the nature of Wierd is such that adding anything at the
31 beginning requires a lot of work to get the rest right, see notes in cat.doc
32 about a Wierd editor).
33
34 See cat.doc for general language notes. In contrast to what is said there,
35 this wire does have comments. Not many, but the important actions are probably
36 somewhere near where the comments say they are.
0 This is not a full program (although it can be run as such), but rather a
1 reusable subroutine. Therefore, input is taken directly from memory, and output
2 is stored back in memory and on the stack. There is no user interaction.
3
4 Input: Numerator in (1,1)
5 Denominator is hard-coded 2
6 Output: Quotient in (1,1)
7 Remainder pushed on the stack
8 Nothing else cluttered
9
10 The algorithm takes O(numerator) time. There might exist a faster algorithm but
11 I don't know it.
0 Just to illustrate exactly how sick I am, this took about three hours,
1 most of which was fidgeting with the editor to make the geometry work.
2
3 OK, I cheated a bit by:
4 -- putting the text in the program
5 -- using the fact that functions with an empty stack are
6 essentially nops
7 And I didn't use anything nifty--no multithreading, genuine conditionals,
8 or anything of the like. Just brute force. I did, however, when I was
9 running out of space, "put" the coordinates in memory so I could just
10 "get" them later.
11
12 Anyway, I found at least one not-quite-as-advertised "feature" in the
13 interpreter. The main one is that a zero on top of the stack does a put
14 of put and get, instead of the expected get, and a non-zero does get
15 instead of put. Since I was doing more getting than putting in the
16 program, I was actually kind of happy, but that means the spec and my
17 comments are wrong (unless you *really* want to declare the least-trivial
18 piece of Wierd code written to date *and* the only currently implemented
19 interpreter non-standard...). The others are really obscure things that I
20 can't figure out how to fix (the gap-jumping doesn't seem to quite work as
21 I understand it).
22
23 Well, I could probably strip out another couple of bytes here and there,
24 but I just don't have the stomach for it today...
25
26 Oh, Ben: If you're going to try a 99-Bottles program, I'd suggest
27 expanding the playing field, since this program clocked in at just under
28 128x128...
29
30 Now I'm going to bang my head against a softer object for a while so I
31 don't notice the pain...
32
33 --John
34
35 P.S. Anybody besides me see the portrait of George Washington in the
36 program? No? I must be hallucinating, then...Oh, well...
0 loop1.w is an infinite loop, which I have tried to write with minimal size (with
1 the restraints that any garbage put on the stack must be taken off again, but
2 that no popping intructions may be performed when there is still data on the
3 stack). It seems at first that the first row and column can be ommited, but
4 this doesn't work, and I suspect broken gap jumping to be the cause.
5
6 loop2.w is also an infinite loop, but with the extra restraint that no threads
7 may be started. Notice how the horizontal line at the bottom can be entered by
8 two parallel paths. The leftmost path is used the first time, afterwards the
9 rightmost path is used. Both have the same angle, therefore the same effect.
10
11 For more information on this broken gap jumping, and the language in general,
12 see cat.doc.
0 This program takes the number at (1,1) (input as the ASCII code of a character)
1 and prints it in binary (I would do decimal but that would require a divide by
2 ten subroutine), using the halving subroutine in half.w. Since it takes the
3 number direct;y from memory, this proram is not quite suitable for the end-user,
4 but rather it can be used as a subroutine in a yet larger program.
5
6 The algorithm takes O(n) time, most of which is spent in the halving subroutine.
0 Note: coordinates (x,y) here mean that y is the higher-on-stack (the row) and x
1 is below it (the column). The "stack" position is, of course, for purposes of
2 getput.
3
4 (1,1) holds the end-of-line character.
5 (1,2) holds the current x coordinate.
6 (2,1) holds the current y coordinate.
7 (2,2) holds the beginnning-of-last-line-of-file character.
8
9 This program is literally spaghetti code. It basically works by getting itself
10 with 135 degree turns, but it uses a few kludges to work around the data in the
11 top-left. Warning: trying to read the code may cause significant loss of
12 sanity. Oh wait a moment, you didn't have any in the first place. Ok, go
13 ahead, read the code, but don't blame me.
14
15 Algorithm:
16 1. Get (1,1) and output (the first line must consist of just one character).
17 2. Push '\n'=10 (with "left, left, left, right, left, right, left, right,
18 left, right, left, right, left, right, left, right, left, right, left,
19 right, left, right, right") and output.
20 3. Put 3 in (2,1).
21 4. Put 1 in (1,2).
22 5. Get (1,3), which was equal to (2,1) at startup, and output.
23 6. Get (2,2) and output (the second line may have only have two characters).
24 7. Push '\n'=10 again (I didn't save it in step 2) and output.
25 8. Get (1,2).
26 9. Get (2,1).
27 10. Get the character specified by the two coordinates at the top of the stack.
28 11. Output it.
29 12. Get ((1,2),(2,1)) again.
30 13. Get (1,1) and compare.
31 14. If equal, go to step 19, otherwise continue with step 15.
32 15. Get (1,2).
33 16. Increment.
34 17. Put it back.
35 18. Return to step 8 and repeat the whole process.
36 19. This is a no-op step to remind you that you can only get here from the
37 conditional in step 14, not from step 18.
38 20. Put 1 in (1,2).
39 21. Push '\n'=10 (yes, I should save it somewhere, but place is limited,
40 particularly in this quine where special locations need special treatment)
41 and output.
42 22. Get (1,(2,1)). Note that this is the first character of the just-finished
43 line.
44 23. Get (2,2) and compare.
45 24. If equal, quit the program. If unequal, continue to step 25.
46 25. Get (2,1).
47 26. Increment.
48 27. Put it back.
49 28. Return to step 8.
50 And that's making it sound simpler than it really is.
51
52 As it happens, the Wierd logo is 42 characters wide. Also, the asterisk, which
53 is the traditional wire character (although it is not treated specially by the
54 computer), has ASCII code 42. Is Wierd the answer to life, the universe, and
55 everything (or to anything, for that matter)?
0 Special data:
1 (1,1): The number so far (starts at 0).
2 (2,2): The negative of the bit to be set (starts at -1).
3
4 (2,2) is doubled each time, and tested for zero. This is an overflow trick that
5 only works on binary computers, and if Wierd is ever ported to ternary
6 computers, this program will run indefinitely or at least much longer than it
7 should.
8
9 In detail:
10 1. Put 0 in (1,1).
11 2. Put -1 in (2,2).
12 3. Get (2,2).
13 4. Push zero (dance "left left right") and subtract. This is necessary because
14 a condition can only follow a 45 or 315 turn (there needs to be space for
15 turning back). Following a 45 turn is quite useless though...
16 5. Test. If zero, go to step 17. Otherwise, continue to step 6.
17 6. Use a 45/315 split to randomly chose whether or not the bit is to be
18 included in the number. Depending on the result, either continue to step 7
19 or jump to step 11.
20 7. Get (1,1).
21 8. Get (2,2).
22 9. Subtract (see why (2,2) is negated now?).
23 10. Put the result back in (1,1).
24 11. Get (2,2).
25 12. Push a zero through the "left left right" dance.
26 13. Get (2,2) again.
27 14. Subtract twice.
28 15. Put the result in (2,2).
29 16. Go back to step 3.
30 17. Get (3,3) and put in (2,2) (for output subroutine).
31 18. Output as a binary number, using output.w.
32 19. Done!
33
34 Since the output routine is O(n), you should modify the interpreter to use a
35 smaller data type (short or even char) if you want the program to terminate this
36 year. Of course, since outputted number is random, you just might be lucky and
37 get a very small number which can be printed in less than a second. The random
38 number generation itself is quite fast.
0 Specification for the Wierd Programming Language--A MicroFunge
1
2 First, a Riddle:
3 Q: What do you get when you put three marginally-sane programmers on a
4 mailing list with the Befunge and BrainF*** programming languages?
5 A: You get BeF***, and then they get Wierd.
6 No, it's not really funny unless you already know what we're talking
7 about. So let's get you up to speed.
8
9 History:
10 The now-defunct Befunge Mailing List once questioned if Befunge was too
11 "top-heavy" a language--that is, if its instruction set was needlessly
12 large. This, as one might expect (especially one reading this
13 specification), quickly degenerated into an argument of "my language is
14 smaller than yours." Ben Olmstead managed to trim down Befunge to a
15 lean seven instructions, dubbing the creation "BeF***".
16 Not to be outdone, it was quickly suggested by John Colagioia that
17 instructions, per se, be eliminated in favor of the "visual programming"
18 aspect of Befunge: The angles made by sequences of instructions. Such
19 a language, of course, would have a single "instruction" from the
20 syntactic standpoint, although it surely cheats by horribly abusing
21 the concept of Euclidean geometry.
22 Chris Pressey then jumped on it, created the angle-to-instruction
23 mapping, and christened the entire mess "Wierd"--a cross between the
24 words "weird" (which the language seemed to be) and "wired" (which
25 would describe the appearance of programs written in the language).
26
27 The Basics:
28 Wierd, like Befunge, is a two-dimensional language with a rectalinear
29 grid of instructions which manipulate a system stack area. Where
30 Befunge has discrete, textual instructions, however, Wierd has a more
31 implicit instruction set, each instruction denoted, not by a symbol, but
32 by a configuration of symbols relative to the current direction of the
33 instruction pointer: the angle of deviation from "straight ahead" from
34 the IP's perpsective. That is, reading from left to right, the
35 following program contains a single instruction:
36 ******
37 *
38 *
39 *
40 and the instruction is "read" as a 45-degree angle to the right.
41
42 The Details:
43 A Wierd source file can be any file, as the language only distinguishes
44 between two symbols: Whitespace and everything else. A chain of non-
45 whitespace symbols makes a Wierd program.
46 Execution begins with the first character of the file (typically
47 considered to be the "upper left" of the program), and the initial
48 direction of the Instruction Pointer is down and to the right. This was
49 chosen to allow the programmer to get away from the corner as
50 efficiently as possible, which reduces the risk of the program becoming
51 trapped.
52 Newlines are defined in a system-dependant manner, though it can be
53 safely assumed on most systems that a carriage return and/or line feed
54 character delineates the end of each line and begins the next.
55 Execution then passes from character to character, in the specified
56 direction until a turn needs to be made.
57
58 Inertia:
59 Like water, the Wierd IP takes the path of least resistance when
60 confronted with a choice. If the Wierd program branches, the IP will
61 always choose the path which is closest to the direction it is already
62 travelling. Therefore, the following code (assuming the IP starts at
63 the left, and travels to the right, like the above):
64 ***********
65 *
66 *
67 *
68 will stay on the top line, and never travel down the branch shown.
69 Should the IP be faced with two equally-likely choices, the branch
70 chosen by the interpreter is undefined, except for one condition which
71 will be treated later.
72
73 (Though, as an implementation note, it should be pointed out that the
74 only existing interpreter at this time chooses the left-hand path.
75 Note that Wierd was not intended to be left-handed, specifically; this
76 is just how the coin showed during the design phase--literally).
77
78 Gap-Jumping:
79 While the above is suitable for a fully-featured programming language,
80 it was quickly realized that programmers could easily (possibly
81 certainly) "paint themselves into a corner," where programs beyond a
82 certain complexity might simply be impossible to write, and would at
83 least be extremely impractical.
84 Therefore, in keeping with the pseudo-electronic motif, the Instruction
85 Pointer was given the ability to launch itself over a limited distance
86 of unused ("empty") programspace to attach to a new program segment.
87 This jumping, to keep it only used in emergency situations, is only
88 usable over a maximum distance of two cells in the program grid.
89 Gap-Jumping follows the same rules as typical movement, regarding
90 Inertia. That is, the IP will choose paths to jump into by how much of
91 a change of direction is required to reach it.
92 Note that jumping a gap into an isolated instruction, like in the
93 following code segment:
94 ***** *
95 is considered an error.
96
97 The Instructions:
98 The Wierd instruction set is based on that of Befunge, though reduced to
99 a nearly-absurd minimalism, and with a certain amount of "stack abuse,"
100 in addition to the abuses already heaped upon the program's geometry.
101 While the People for the Ethical Treatment of Data Structures threatened
102 to protest, they quickly realized that their acronym was not easily
103 pronounced, and retreated to debate the merits of a new name before
104 further business could be discussed.
105 The instructions, listed by angle, are:
106 0 degrees NO: No operation, continue as normal.
107 45 degrees P1: Push a data value of 1 onto the stack.
108 90 degrees IF: Pop the stack. If the value is zero, continue
109 executing as normal. If the value is nonzero,
110 however, reverse direction.
111 135 degrees GP: Pop the stack. If the value is zero, pops the next
112 two items from the stack, retrieves (gets) the
113 value stored at the coordinates specified by these
114 values (x, then y), and push it onto the stack. If
115 the first value was nonzero, however, takes the
116 value stored below the coordinates on the stack,
117 and stores (puts) it at the coordinates.
118 180 degrees QU: Jump the gap, if possible. Otherwise, terminate.
119 225 degrees IO: Pop the stack. If the value is zero, read a
120 character from input, pushing it onto the stack.
121 If the value was nonzero, pop the stack, and print
122 the value to output as a character.
123 270 degrees IF: See 90 degrees. Included for flexibility.
124 315 degrees SB: Subtract the top of the stack from the value
125 beneath it, popping both values, and pushing the
126 result.
127 Note that pushing a 1 is the only form of direct data specification
128 available to the programmer, and subtraction is the only available
129 arithmetic operation.
130
131 Concurrency:
132 The exception mentioned above to the "always choose a single path" rule
133 is when the two likeliest paths are at angles of both 90 and 270
134 degrees--both forms of conditional. In such a case, rather than
135 choosing one or the other, both paths are chosen, and the IP is cloned
136 (including stack) to cover the other path.
137
0 0 ******
1 * * *
2 * * *
3 * * *
4 ************* *
5 *
6 ****** *
7 * * *
8 * * *
9 * * *
10 ***** * *
11 * * *
12 * * *
13 * * *
14 * * *
15 * * *
16 * * *
17 * * *
18 **** * *
19 * * *
20 * * *
21 * * ****
22 * * *
23 * *
24 * *
25 *********
26
0 * *****************
1 * * *
2 * * ** *
3 * * * * *
4 * * * * *
5 * * * * *
6 * * * * *
7 * * * * *
8 * * ***************
9 * * *
10 * * *
11 * * *
12 * * *
13 * ********** *
14 * * * * *********** *
15 * * * * * * * *
16 * * ** * * * ****** * **
17 * * * * ** * * * * **
18 * *** ** * ** * * *
19 * * * * * * *
20 * * * * * *
21 * **** ***** * *
22 ** * *
23 ****
0 * ******
1 * * *
2 * * *
3 * * *
4 ************* *
5 *
6 *
7 **************
8 * *
9 * *
10 * *
11 * *
12 * *
13 * *
14 * *
15 * *
16 * *
17 * *
18 * *
19 * *
20 * *
21 * ****
22 * *
23 * *
24 * *
25 *********
26
0 * ******
1 * * *
2 *** *
3 *
4 *
5 * *
6 **
7 *
8
0 * ******
1 * * *
2 * * *
3 * * * *
4 * *** *
5 ** *
6 * *
7 * *
8 * *
9 * *
10 * ***
11 ** *
12
0 * ****** *
1 * * * * *
2 * * * * *
3 ********** * * *
4 * ** *
5 * * *
6 * * *
7 * * *
8 * * *
9 * * *
10 * * *
11 * * *
12 ********************************************
13 * * * *
14 * * * *
15 * * * *
16 * * * *
17 * * * *
18 * * * *
19 * * * *
20 * * * *
21 * * * *
22 **************** * * *
23 * * * * * *
24 * * * * * *
25 * * * * * *****
26 * * **** * * *
27 * * * * * *
28 * * * * *
29 * **** * * *
30 * * * *
31 * * * *
32 * * ************************
33 * *
34 * *
35 * *
36 * *
37 * *
38 * *
39 * *
40 * *
41 * *
42 * *
43 * *
44 * *
45 * *
46 * *
47 * *
48 * *
49 * *
50 * *
51 * *
52 * *
53 * *
54 * *
55 * *
56 **
57 *
58
0 *
1 *
2 *
3 *
4 *
5 *
6 *
7 *
8 *
9 *
10 *
11 * ****** *
12 * * * * * *
13 * * * * * *
14 * ********** * * *
15 * * ** *
16 * * * *
17 * * * *
18 * * * *
19 * * * *
20 * * * *
21 * * * *
22 * * * *
23 * ******************************************
24 * * * * * *
25 * * * * * *
26 * * * * * *
27 * * * * * *
28 * * * * * *
29 * ** * * * *
30 * * * * * *
31 * * * * * *
32 * * * * *
33 **************** * * *
34 * * * * * *
35 * * * * * *
36 * * * * * *****
37 * * **** * * *
38 * * * * * *
39 * * * * *
40 * **** * * *
41 * * * *
42 * * * *
43 * * ************************
44 * *
45 * *
46 * *
47 * *
48 * *
49 * *
50 * *
51 * *
52 * *
53 * *
54 * *
55 * *
56 * *
57 * *
58 * *
59 * *
60 * *
61 * *
62 * *
63 * *
64 * *
65 * *
66 * *
67 **
68 *
69
0 0
1 9
2 *
3 *
4 *
5 * PUT
6 *
7 * *
8 * **
9 * * *
10 * * *
11 * * *
12 * * *
13 * **********************************
14 * * *
15 * *** *
16 * * *
17 * * *
18 * * *
19 * * *
20 * ************** *
21 * * * * * *
22 * * * * * *
23 * * * * *
24 * * * * * *** *
25 * * * * GET ********** *** * *
26 * * * END * * *** * *
27 * * * * ** *** *
28 * * * * * *** *
29 * * *** * * * *
30 * * * * * * *
31 * * * ADD ONE * * * *
32 * * * * DONE? * * *
33 * * * * * * *
34 * * * * * * *
35 * * * *************** * *
36 * * * * * GET * *
37 * * * * ** * *
38 * * * * * * * *
39 * ********* * * * * *
40 * * * * * *
41 * GET AGAIN * * * * *
42 *** * * * *
43 * * * * * *
44 * * *** * *
45 * * * *
46 * *** * * *
47 * * ** * *
48 * * * * *
49 * * * *
50 * * WRITE * *
51 * * * *
52 * * * *
53 * * * *
54 * * * *
55 * * * *
56 * * * *
57 * * * *
58 * *** * * *
59 * * * * * *
60 *** * ** *
61 * * *
62 * *
63 * GET AGAIN *
64 * *
65 * **************************
66 * *
67 * *
68 * *
69 * *
70 * *
71 *
72
0 + *
1 * **
2 * * *
3 * * * **
4 * **************************** *
5 * * * * *
6 * * * * *
7 * * * * *
8 * **RESTART*** *
9 * * * *
10 * **LOOP** *
11 ** * * *
12 * ** * *
13 ** * ** ** *
14 * ***** * * * * *
15 * * * * * * *
16 * * * *********** **** *
17 ********** * * * *
18 * * * * * **
19 * * ******* * * *
20 ** * * * * *********** *
21 ** * * ** * * * * *
22 *** ** * * * * * * *
23 * * * *********** * * * *
24 * **DEHSINIF** * * ** *
25 * * * F * *
26 * * * I * *********
27 * ** * N **
28 * ** I
29 * * S
30 * H
31 * **E*****
32 *** * D *
33 * * * *
34 ********* * * *
35 * * * ** **
36 * * * *
37 * * * *
38 * * * *
39 * * *
40 * *
41 * * **
42 ******************* *
43 **
44 *
45 * *
46 * * *
47 * * *
48 * * D
49 ** O
50 N
51 E
52 !
53 *
54 *
55
0 H ************************ ****************** **********
1 e * * * * * * *
2 l * *** * ** * * * * *
3 ! o * *** * * * * * * * * *
4 , * * * ** * * * * * * * *
5 W * * * * * * * * * * * ** *
6 r * * * * * * ************ * * * * * * *
7 d * * * * * * * * ****** * * * * *
8 * * * * * ** ** * * * * * * *
9 * ** * * * * * * * ** * *
10 * * * * * * ** ** * * * * *
11 * * * * * ** ** * ** * * * *
12 ******************** * * * ** * ** **** *** *
13 * ** * * ** * ** *
14 * ** * * * ** * ** *
15 * ** * ** * ** ** * ** *
16 ***** * ** * * ** ** ** *
17 ** * * ** *
18 * * *
19 ************************************************************* * *****************************
20 * * *
21 * *** * *
22 * * * * * *
23 * ** * * * *
24 * * * * ** ****** * *********************
25 * * * * * * * * *
26 * * * * * * * * *
27 * * * * ** * * * *
28 * * * * ** * * * *
29 * * * ***** ** * * * *
30 * * ** * ** ** * * * *
31 * * ** * ** ** ***** * * *
32 * * ** * * ** * * *
33 * * ** ** * * ** * ** *
34 * * * ** ***** ** ** * ** *
35 * * * ** ** * * *
36 * * ** ** * * *
37 ** * ** * ** *
38 * * * * *
39 * * ************************************************************* * * *
40 ** * * * * * *
41 ** * * * * * * *
42 * * * ************************* ** * * * *
43 * * * * * * * * * * *
44 *** * * * * * * * * * * ************** *
45 * * * * ** * * * * * ** ** * *
46 * * * * * * *** * * * * ** ** ******* *
47 ** * * * ** * * * * ** * *
48 * * * * * * * * ** * *
49 * * * * * * * ** * *
50 * * * * * * * ** * *
51 * * * * * * * * ** * *
52 * * * * * ** * * ** * *
53 * * * * * * * * * * * *
54 * * * * * * * * * * * *
55 * * * * ** * * * * * *
56 * * * * * * * * * * *
57 * * * * * * * ** *
58 * * * * * * * * *
59 * * * * * * * *
60 * * * ***** * * *
61 * * * * * *
62 * * * * * *
63 * ** * * *
64 * * * * *
65 * * * *
66 ***************************** * *
67 * *
68 *********************************************************************************************** *
69 * *
70 * *
71 * ** *
72 * ** ** *
73 * ** * *
74 * ** * *
75 * ** * *
76 * ** * *
77 * ** * ****** *
78 * **** ** * * * ******************
79 * * * ** ** ** * *
80 * * * ** ** * ** *
81 * * * * * *
82 * * * * * *
83 * ***** * * * *
84 * * * * * *
85 * * ** * *
86 * * * * *
87 * * * *
88 ******* * *
89 ** ** *
90 ** ** * *
91 ** ** * **
92 ************************ ** ** * * *
93 * ** * * *
94 * * * * *
95 * ** * * *
96 * * * * * *
97 * * * * * *
98 * * * ** *
99 * * ** * *
100 * * ** *
101 * * ** *
102 ** ** *
103 * ** ******************************
104 ** ** **
105 ** ** **
106 ** ** **
107 ** * **
108 * **
109 * **
110 * **
111 * ** ** **
112 *************** ** **
113 **
114
115 * ** ** **
116
117 *************** ** **
118
119
0 *
1 *
2 *
3 *
4 * * **
5 * ** *
6 ** **
7 * *
8 * *
9 * *
10 * *
11 * **
12 * *
13 * ** *
14 ** *
15
0 * *
1 * * *
2 * * ***
3 * * *
4 * * *
5 * * *
6 * * *
7 * * *
8 * *** *
9 * * *
10 * * *
11 * * *
12 * * *
13 * * *
14 * * *
15 * * *
16 * * *
17 * * ***
18 * * *
19 *******
20
0 & *
1 0 * *
2 * * *
3 * ** *
4 ** *
5 * ****************************
6 * *********** *
7 * * *
8 ** * *
9 * ** *
10 *H * * *
11 * A * * ** *
12 * L **************************** * *
13 * F * * * * *
14 N * * * * * *
15 E * * * * * *
16 X * **RESTART*** * *
17 T * * * * *
18 * * * **LOOP** * *
19 * * ***** * * * *
20 * * * ** * * *
21 * ** ** * ** ** * *
22 * * * ***** * * * * * *
23 * * * * * * * * * *
24 ** * * * * *********** **** * *
25 * ********** * * * * *
26 * * * * * ** *
27 * * ******* * * * *
28 ** * * * * *********** * *
29 ** * * ** * * * * * *
30 *** ** * * * * * * * *
31 * * * *********** * * * * *
32 * **DEHSINIF** * * ** * *
33 * * * F * * *
34 * * * I * ********* *
35 * ** * N ** *
36 * ** I *
37 * * S *
38 * H *
39 * **E***** *
40 *** * D * *
41 * * * * *
42 ********* * * * *
43 * * * ** ** *
44 * * * * *
45 * * * * *
46 * * * * *
47 * * * *
48 * * *
49 * * ** * *
50 ******************* * ** *
51 ** * * *
52 * ** * * * *
53 * ** * * * * ** *
54 * ** * * * * ** *
55 * * * * * * * *
56 *** * * * ** * * *
57 * * ** * * * *
58 * **** H * * *
59 * * * * A* * *
60 * * **OREZ** L * *
61 ****PRINT* * * * * *V * *
62 * * * * * * E * *
63 * * ** * ** * D ** *
64 * * ** * ** * ** *
65 ************* * * * * *
66 * * * * * * * * *
67 * * * * D * **IICSA** *
68 ** * * O * * * *
69 * ***** N * * * *
70 E * ** *
71 * * * *
72 ( * *
73 P ** *
74 R * *
75 I * *
76 N * *
77 T * *
78 * * *
79 N * *
80 E *****************
81 W
82 L **
83 I ** ****
84 N ** *
85 E ** *
86 ) ** *
87 * ** *
88 * **
89 * **
90 * **
91 * **
92 **
93
0 DONOTWierd *
1 DO,1<- # 0 09
2 DO,1SUB#1 <- # 01 10
3 PLEASEDO,1SUB # 2 <- #0 3 2
4 DO,1SUB # 3 <- #0 7 2
5 DO ,1SUB#004<-#0 0 0 0 000000136
6 DO,1SUB#5 <- # 0 0 0 8 8
7 PLEASEDO,1SUB # 06 <- # 0 1 3 6
8 DO , 1SUB#7 <- # 000 0 6 4
9 DO ,01 SUB #8 <- # 0 0 0 0 0 80
10 DO ,1 SUB # 00 0 0 0 0 9 <-#2 26
11 PLEASE READ OUT ,0 0 0 0 0 000000000000000 0 0 01
12 PLEASEGIVEUPDONOTBOTHERME * * * P * * * * * **
13 DONOT * * * * * O* * * * * * **
14 DONOT ** * * * O ** * * ** * * **
15 DONOT ** * * *L * * ** * * * **
16 PLEASEDONOT * * * * * ** * ** * * **
17 DONOT * * * * N* * * * * * * **
18 DONOT * * * * I ** ** * * * **
19 DONOT * * * * A * * * * * *
20 PLEASEDO NOT * * * M ** ** * * * *
21 DONOT * * * * * * * * * ** ** *
22 DONOT * * * * * * ** * ** * * *****************
23 DONOT * * * * * * * ********* * ** *
24 PLEASEDONOT **** * * ** ** *
25 DONOT * ** * * * * *
26 DONOT ** * * * * * *
27 DONOT * ** * * *
28 PLEASEDONOT * * * * *
29 DONOT *********** * * *
30 DONOT * * * * * *
31 DONOT * * * * *
32 PLEASEDONOT * * * * * *
33 DONOT * * * * *
34 DONUT * * * * * *
35 DONOT * * * * * *
36 PLEASEDONOY * * * * * *
37 DONOT * * * * * *
38 DONOT * * * * * *
39 DONOT * * * * * W
40 PLEASEDONOT * * * * * R
41 DONOT * ** * * I
42 DONOT * * * *T
43 DONOT * * E
44 DONOT * *
45 OKAY,DOIFYOUPLEASE!
46 ICHANGEDMYMINDDON'T
47 DONOTDOTHAT **
48 PLEASESTOP *
49
0 !
1 @
2 * !
3 * *!
4 * * !
5 * * !
6 * * * !
7 * * * !
8 * *** * !
9 ** * * !
10 * ** ** * **!
11 * * ** **** * * !
12 * ** * * ** !
13 * ** * * * * !
14 * ** * * * * *** * !
15 * ** * * * * * * * * !
16 * ** * * * * * * * * * !
17 * ** * * * ** * * * * * *!
18 ** * * * *** * * * * * * * !
19 * * * * * * * * * * !
20 *** * ** * * * * * * !
21 * * * * * * * * !
22 * * * * * * * * * !
23 * * * * * ** *** * * * !
24 * * * * * * ** * * * * !
25 * * * * * * **** * * * !
26 * ** * * * * * * **************************!
27 * * * * * * * * * * !
28 * * * * * * * * * * !
29 * * * * * * * * * * !
30 * * * * * * * * * ********************** !
31 * * * * * * * * * * * !
32 * * ***** *** * * * * * * * ** !
33 * * * ** * * * * * * * !
34 * * * * * * * * * * **** * * * !
35 * * * * * * * * * * * * * ** * !
36 * * * * ** * * * * * * ********* * * !
37 * * * * ** * * * ** * * * * ** !
38 * * * ** ** * * * * * * * * * !
39 * ** * * * * * * * * * * * !
40 * * * * * * * ** * * * !
41 ********************************************************* * * * * ** * * * * !
42 * * * * * * * * * * !
43 __ ___________________ _____ * * * * * * * * * * !
44 \ \ / __ __ ___ _ \ | __ \ * * * *RESTART* ** * * * !
45 \ \ /\ / / | | | |_ | |_) \| | \ \ * * * * * * ** * * !
46 \ \/ \/ / | | | _| | _ /| | ) ) * * * **RESTART* ** * * * * !
47 \ /\ / __| |__| |___| | \ \| |__/ / * * * * * * * * * * ** !
48 \/ \/ |_______________| \_______/ * **************** ****MAIN*LOOP**** * * * * * !
49 ____ _ _____________ ____ ** * * * ** * ** * !
50 / __ \ | | | __ __ \ | __| ** * * * ** ** * * !
51 / / \ \ | | | | | | | |\ \ | |_ * * * ** ** * !
52 ( ( ) )| | | | | | | | \ \ | _| * * * * * * * !
53 \ \__/ \| |_| |__| |__| | \ \| |__ ** * * ****YAW*SIHT****** * !
54 \____/\_________________| \______| * * * * * * * * !
55 ********WON*1=X**** ** * ***** ** * !
56 ____ ____ ___ ___ ___ * * * * * * * !
57 / __ \ / _ \ / _ \ / _ \ / | * * ** * * * * * !
58 / / \ \ (_/ ) / / / \ \ / / \ \ (_/| | * * E * * * * * !
59 ( ( ) / / ( ( ) )( ( ) ) | | * *O * ** * * * * !
60 \ \__/ / / /__ \ \_/ / \ \_/ / __| |__ * L * * * * * * !
61 \____/ /_____| \___/ \___/ |_______| * ** * * * * * * !
62 __ ____ ___ ___ ____ * * * * * * *********** !
63 / \ / _ \ / _ \ / _ \ / _ \ * * * * * * * !
64 ( () ) _ (_/ ) / / / \ \ / / \ \ (_/ ) / * * * * * * * !
65 ) _ \/ ) / / ( ( ) )( ( ) ) / / * * ** **** * ** ***** !
66 ( (_) ( / /__ \ \_/ / \ \_/ / / /__ * * * * ** ** !
67 \___/\_) /_____| \___/ \___/ /_____| * * * ** !
68 __ ____________ ____ * * * !
69 | \ / __ __ | / __ \ * * * !
70 | \ / | | | | | / / \ \ * *** !
71 | |\ \/ /| | | | | | ( ( ) ) * !
72 | | \ / | |__| |__| |_____) \__/ / * !
73 |_| \/ |_______________________/ * !
74 __ ___ _ * !
75 \ \ /\ | \ | | * !
76 \ \ / \ | |\ \ | | * !
77 \ \/ /\ \| | \ \ | | * !
78 \ ____ \ | \ \| | * !
79 \/ \__| \___| * !
80 _ _ ___ _____ _______ *** !
81 | | | | /\ | \ | __ \ | ___ | * * !
82 | |__| | / \ | |\ \ | | \ \| |_ | | * !
83 | __ | / /\ \| | \ \ | | ) ) _| | | * * !
84 | | | |/ ____ \ | \ \| |__/ /| |___| |___ * * * * !
85 |_| |___/ \__| \_______/ |___________| * D * ** !
86 * O * * * !
87 SOURCE AND OUTPUT BOTH LICENCED BY THE GPL * * N ******* * * !
88 (DOESN'T FIT WITH ASCII ART) * ** E * * * * !
89 * * * ******* * * !
90 ** * * * * * !
91 * * * N * * !
92 *** * O * * !
93 * * ** * T * ** !
94 * ** ** * * !
95 *** * Y * !
96 * E * !
97 * T * !
98 * ** !
99 * !
100 * !
101 * !
102 * !
103 * *!
104 ** * *!
105 ** ** !
106 * !
107 * ****************************!
108 @ *!
109
110
111
0 * ** *
1 * * ** * **
2 0 ** **** ** * * *
3 * * ** * * ** ** * *
4 * * * ** * ** * *
5 * * * * * * ** * *
6 * * ** * * * * * *
7 **** * * * * * *
8 * * * * * * *
9 * * * * * * *
10 * * * * * * *
11 ** * * * * *
12 * * * * * *
13 ** * * * ******
14 * * * * * * *
15 * * * * * * * * *
16 * * ** * * * * * *
17 * * * * * * ****** *
18 * * * * ** *
19 * ** * * N ******** *
20 * ** * * ******E******* * * *
21 M ** * S * ** * ** * *
22 A * O ** * * * * *
23 I * H * * * *
24 N * C * * * *
25 * * * * * * * *
26 L * R ** ** * * *
27 O * E * * * ** *
28 O * B * * * ** * *
29 P * M * ** * * *** *
30 * * U * ** * * * *
31 ** N * * * * * *
32 * * * * * * * *
33 * * ** * * * * * *
34 ** **** * * * * * * *
35 ** * * * * * * * *
36 * **** * * * * * * *
37 * ** * **** * * ** * *
38 ** * * * * * *
39 ***************** * *
40 * * * ** *
41 * * * * *
42 * * * * *
43 * * * *
44 * * ** * *
45 * * **************** *
46 * ** *
47 * * *
48 ****** * *
49 * * * * *
50 * ** * *
51 * *** *
52 * * *
53 * ** * *
54 * **** * * *
55 * * * * *
56 * * * * *
57 ** * * * *
58 ** * *** *
59 * * ** *
60 * * *
61 ** *
62 * *
63 * *
64 * * *
65 * * *
66 * ** *
67 ** *
68 * ****************************
69 * *********** *
70 * * *
71 ** * *
72 * ** *
73 *H * * *
74 * A * * ** *
75 * L **************************** * *
76 * F * * * * *
77 N * * * * * *
78 E * * * * * *
79 X * **RESTART*** * *
80 T * * * * *
81 * * * **LOOP** * *
82 * * ***** * * * *
83 * * * ** * * *
84 * ** ** * ** ** * *
85 * * * ***** * * * * * *
86 * * * * * * * * * *
87 ** * * * * *********** **** * *
88 * ********** * * * * *
89 * * * * * ** *
90 * * ******* * * * *
91 ** * * * * *********** * *
92 ** * * ** * * * * * *
93 *** ** * * * * * * * *
94 * * * *********** * * * * *
95 * **DEHSINIF** * * ** * *
96 * * * F * * *
97 * * * I * ********* *
98 * ** * N ** *
99 * ** I *
100 * * S *
101 * H *
102 * **E***** *
103 *** * D * *
104 * * * * *
105 ********* * * * *
106 * * * ** ** *
107 * * * * *
108 * * * * *
109 * * * * *
110 * * * *
111 * * *
112 * * ** * *
113 ******************* * ** *
114 ** * * *
115 * ** * * * *
116 * ** * * * * ** *
117 * ** * * * * ** *
118 * * * * * * * *
119 *** * * * ** * * *
120 * * ** * * * *
121 * **** H * * *
122 * * * * A* * *
123 * * **OREZ** L * *
124 ****PRINT* * * * * *V * *
125 * * * * * * E * *
126 * * ** * ** * D ** *
127 * * ** * ** * ** *
128 ************* * * * * *
129 * * * * * * * * *
130 * * * * D * **IICSA** *
131 ** * * O * * * *
132 * ***** N * * * *
133 E * ** *
134 * * * *
135 ( * *
136 P ** *
137 R * *
138 I * *
139 N * *
140 T * *
141 * * *
142 N * *
143 E *****************
144 W
145 L **
146 I ** ****
147 N ** *
148 E ** *
149 ) ** *
150 * ** *
151 * **
152 * **
153 * **
154 * **
155 **
156
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3 #include <time.h>
4 #include <unistd.h>
5 #include <getopt.h>
6
7 typedef struct stack
8 {
9 int value;
10 struct stack *below;
11 } stack;
12
13 typedef struct thread
14 {
15 int id;
16 int x, y, dx, dy;
17 stack *stack_head;
18 struct thread *next, *prev;
19 } thread;
20
21 int size = 256;
22 int debug = 0;
23 int **world;
24 thread *current_thread;
25 int threads = 0;
26
27 void push(int value)
28 {
29 stack *new;
30
31 new = malloc(sizeof(*new));
32 new->value = value;
33 new->below = current_thread->stack_head;
34 current_thread->stack_head = new;
35 }
36
37 int pop(void)
38 {
39 stack *old;
40 int value;
41
42 old = current_thread->stack_head;
43 if(old == NULL)
44 {
45 fprintf(stderr, "Insufficient stack!\n");
46 exit(1);
47 }
48 value = old->value;
49 current_thread->stack_head = old->below;
50 free(old);
51 return value;
52 }
53
54 void copy_stack(thread *dst, thread *src)
55 {
56 stack *dst_loc, *prev_dst_loc = NULL, *src_loc;
57
58 if(src->stack_head == NULL)
59 {
60 dst->stack_head = NULL;
61 return;
62 }
63 for(src_loc = src->stack_head; src_loc != NULL; src_loc = src_loc->below)
64 {
65 dst_loc = malloc(sizeof(*dst_loc));
66 dst_loc->value = src_loc->value;
67 dst_loc->below = NULL;
68 if(prev_dst_loc == NULL) dst->stack_head = dst_loc; else prev_dst_loc->below = dst_loc;
69 prev_dst_loc = dst_loc;
70 }
71 }
72
73 void new_thread(void)
74 {
75 thread *new;
76
77 new = malloc(sizeof(*new));
78 new->id = threads++;
79 new->x = current_thread->x;
80 new->y = current_thread->y;
81 new->dx = -current_thread->dx;
82 new->dy = -current_thread->dy;
83 copy_stack(new, current_thread);
84 new->next = current_thread->next;
85 new->prev = current_thread;
86 current_thread->next->prev = new;
87 current_thread->next = new;
88 }
89
90 void kill_thread(void)
91 {
92 thread *old;
93
94 old = current_thread;
95 while(old->stack_head != NULL) pop();
96 if(old->next == old) exit(0);
97 old->prev->next = old->next;
98 old->next->prev = old->prev;
99 current_thread = old->next;
100 free(old);
101 }
102
103 void turn_dxdy(int *dx, int *dy, int direction)
104 {
105 int old_dx, old_dy;
106
107 direction %= 8;
108 if(direction < 0) direction += 8;
109 while(direction-- > 0)
110 {
111 old_dx = *dx;
112 old_dy = *dy;
113 *dx = old_dy + old_dx;
114 *dy = old_dy - old_dx;
115 if(abs(*dx) == 2) *dx /= 2;
116 if(abs(*dy) == 2) *dy /= 2;
117 }
118 }
119
120 int can_turn(int direction)
121 {
122 int dx = current_thread->dx, dy = current_thread->dy;
123
124 turn_dxdy(&dx, &dy, direction);
125 return world[current_thread->x + dx][current_thread->y + dy] != ' ';
126 }
127
128 void turn(int direction)
129 {
130 turn_dxdy(&current_thread->dx, &current_thread->dy, direction);
131 }
132
133 void print_stack(void)
134 {
135 char str1[256], str2[256] = "";
136 stack *printing;
137
138 fprintf(stderr, "The new stack is");
139 if(current_thread->stack_head == NULL)
140 {
141 fprintf(stderr, " empty.\n");
142 return;
143 }
144 for(printing = current_thread->stack_head; printing != NULL; printing = printing->below)
145 {
146 sprintf(str1, " [%d]%s", printing->value, str2);
147 strcpy(str2, str1);
148 }
149 fputs(str2, stderr);
150 fputc('\n', stderr);
151 }
152
153 void help(void)
154 {
155 fprintf(stderr, "Valid options:\n");
156 fprintf(stderr, "-help: Show this screen.\n");
157 fprintf(stderr, "-size <number>: Set the memory size.\n");
158 fprintf(stderr, "-debug: Print debugging information.\n");
159 fprintf(stderr, "There should also be a non-option argument naming the program to be run.\n");
160 exit(1);
161 }
162
163 int main(int argc, char **argv)
164 {
165 struct option options[] = {{"help", 0, NULL, '?'},
166 {"size", 1, NULL, 's'},
167 {"debug", 0, NULL, 'd'}};
168 int done = 0;
169 char *ptr;
170 int x, y;
171 char *in_name = NULL;
172 FILE *in_file;
173
174 opterr = 0;
175 while(!done)
176 {
177 switch(getopt_long_only(argc, argv, "-?", options, NULL))
178 {
179 case 's': if(*optarg == '\0') help();
180 size = strtol(optarg, &ptr, 10);
181 if(*ptr != '\0') help();
182 break;
183 case 'd': if(debug) help();
184 debug = 1;
185 break;
186 case '?': help();
187 case 1: if(in_name != NULL) help();
188 in_name = strdup(optarg);
189 break;
190 case EOF: done = 1;
191 break;
192 }
193 }
194 if(in_name == NULL) help();
195 world = malloc(sizeof(*world) * size);
196 for(x = 0; x < size; x++)
197 {
198 world[x] = malloc(sizeof(**world) * size);
199 for(y = 0; y < size; y++) world[x][y] = ' ';
200 }
201 in_file = fopen(in_name, "r");
202 if(in_file == NULL)
203 {
204 perror(in_name);
205 return 1;
206 }
207 y = 1;
208 for(;;)
209 {
210 char ch;
211
212 x = 1;
213 for(;;)
214 {
215 ch = fgetc(in_file);
216 if(ch == '\n' || ch == EOF) break;
217 world[x++][y] = ch;
218 }
219 if(ch == EOF) break;
220 y++;
221 }
222 fclose(in_file);
223 if(world[1][1] == ' ')
224 {
225 fprintf(stderr, "Starting point for program is empty.\n");
226 return 1;
227 }
228 current_thread = malloc(sizeof(*current_thread));
229 current_thread->id = threads++;
230 current_thread->x = current_thread->y = 1;
231 current_thread->dx = current_thread->dy = 1;
232 current_thread->stack_head = NULL;
233 current_thread->next = current_thread->prev = current_thread;
234 srandom(time(NULL));
235 for(;;)
236 {
237 int closest_right = 4, closest_left = 4;
238 int which, x, y;
239
240 if(debug) fprintf(stderr, "Thread %3d at (%3d,%3d) ", current_thread->id, current_thread->x, current_thread->y);
241 if(can_turn(1)) closest_left = 1; else if(can_turn(2)) closest_left = 2; else if(can_turn(3)) closest_left = 3;
242 if(can_turn(-1)) closest_right = 1; else if(can_turn(-2)) closest_right = 2; else if(can_turn(-3)) closest_right = 3;
243 if(can_turn(0))
244 {
245 if(debug) fprintf(stderr, "is happily marching along (0 degrees).\n");
246 }
247 else if(closest_left == closest_right)
248 {
249 switch(closest_left)
250 {
251 case 1: if(debug) fprintf(stderr, "faces a difficult choice (45 or 315 degrees).\n");
252 if(random() & 1024) turn(1); else turn(-1);
253 break;
254 case 2: if(debug) fprintf(stderr, "spawns a new thread (90 and 270 degrees).\n");
255 turn(2);
256 new_thread();
257 current_thread = current_thread->next;
258 continue;
259 case 3: if(debug) fprintf(stderr, "is confused (135 and 225 degrees).\n");
260 fprintf(stderr, "The programmer has not yet decided what a 135/225 T-junction should do!");
261 return 1;
262 case 4: if(debug) fprintf(stderr, "bumps into a dead end (180 degrees).\n");
263 kill_thread();
264 continue;
265 }
266 }
267 else if(closest_left < closest_right)
268 {
269 switch(closest_left)
270 {
271 case 1: if(debug) fprintf(stderr, "places a one on his stack (45 degrees).\n");
272 push(1);
273 break;
274 case 2: which = pop();
275 if(which)
276 {
277 if(debug) fprintf(stderr, "is afraid from the turn (90 degrees).\n");
278 turn(2);
279 break;
280 }
281 if(debug) fprintf(stderr, "happily marches through the turn (90 degrees).\n");
282 break;
283 case 3: which = pop();
284 y = pop();
285 x = pop();
286 if(which)
287 {
288 if(debug) fprintf(stderr, "gets a number for his stack (135 degrees).\n");
289 push(world[x][y]);
290 }
291 else
292 {
293 if(debug) fprintf(stderr, "puts a number in his stack down (135 degrees).\n");
294 world[x][y] = pop();
295 }
296 break;
297 }
298 if(debug) print_stack();
299 turn(closest_left);
300 }
301 else
302 {
303 switch(closest_right)
304 {
305 case 1: if(debug) fprintf(stderr, "sits down to work out a subtraction (315 degrees).\n");
306 y = pop();
307 x = pop();
308 push(x - y);
309 break;
310 case 2: which = pop();
311 if(which)
312 {
313 if(debug) fprintf(stderr, "is afraid from the turn (270 degrees).\n");
314 turn(-2);
315 break;
316 }
317 if(debug) fprintf(stderr, "happily marches through the turn (270 degrees).\n");
318 break;
319 case 3: which = pop();
320 if(which)
321 {
322 which = pop();
323 if(debug) fprintf(stderr, "wishes you to know that \"%c\" (225 degrees).\n", which);
324 if(!debug || !isatty(1)) putchar(which);
325 }
326 else
327 {
328 which = getchar();
329 if(debug) fprintf(stderr, "discovers that \"%c\" (225 degrees).\n", which);
330 push(which);
331 }
332 break;
333 }
334 if(debug) print_stack();
335 turn(-closest_right);
336 }
337 current_thread->x += current_thread->dx;
338 current_thread->y += current_thread->dy;
339 current_thread = current_thread->next;
340 }
341 }
342
0 /*
1 * Wierd Interpreter:
2 *
3 * Wierd Language developed by Chris Pressey, August 1997
4 * Interpreter written 05 August 1997 by John Colagioia
5 *
6 * Deviations from the "Official" Wierd:
7 * Direction: The IP will always try to continue in the same
8 * direction (or as close as possible). When two
9 * equally-likely possibilities exist, it will choose
10 * the "leftmost" branch.
11 * Conditionals: When the IP connects to a 90-degree angle,
12 * it pops the stack. If the result is zero, it
13 * continues as if nothing interesting happens. If
14 * nonzero, it reverses the IP direction.
15 * Gap-Sparking: If the IP has just "sparked into" a
16 * location which is isolated, the program is
17 * considered erroneous, as the IP direction is
18 * undefined at that time.
19 *
20 * Revision History:
21 * R#: Date: Inits: Reason:
22 * 0 05aug97 jnc Origination
23 * 1 06aug97 jnc Various Bugfixes, Revised Conditionals
24 * 2 07aug97 jnc Added Multithreading, Revised Conditionals
25 * 3 08aug97 jnc Added "Gap-Sparking"
26 * 4 08aug97 jnc General Cleanup and Bugfixes
27 *
28 * To Do:
29 * -- Heavier testing (requires writing Wierd code...).
30 * -- Add a tty or graphical display routine.
31 *
32 */
33
34 /*** Preprocessor Directives ***/
35 /* Included header files */
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <malloc.h>
39 /* Constants and Macros */
40 #define SIZE 128
41
42 /*** Data Structures ***/
43 struct iplist /* An instruction pointer */
44 {
45 int ipid; /* A unique identifier */
46 int x; /* The current ordinate value */
47 int y; /* The current abscissa value */
48 int dx; /* The next change in x to be applied */
49 int dy; /* The next change in y to be applied */
50 int stack[SIZE]; /* A stack exclusive to this IP */
51 int s_top; /* A pointer to the stack top */
52 struct iplist *next; /* The next IP available */
53 };
54
55 /*** Function Prototypes (only for the function table below) ***/
56 int nop (struct iplist **);
57 int push1 (struct iplist **);
58 int subtract (struct iplist **);
59 int condition (struct iplist **);
60 int getput (struct iplist **);
61 int inputoutput (struct iplist **);
62 int terminus (struct iplist **);
63
64 /*** more prototypes, because my compiler likes them - cap */
65 int turn45 (int * xdir, int * ydir);
66 int getnextturn (int x, int y, int * dx, int * dy);
67
68 /*** Global Variables ***/
69 char workspace[SIZE][SIZE]; /* The "Wierd memory space" */
70 int tmpx, tmpy, /* temporary deltas */
71 ipid = 0, ip_killed; /* IP identifier, kill flag */
72 struct iplist *list; /* The list of IPs */
73 int (*function[])(struct iplist **) =
74 { /* Function table */
75 nop, /* 0 degrees */
76 push1, /* 45 degrees */
77 condition, /* 90 degrees */
78 getput, /* 135 degrees */
79 terminus, /* 180 degrees */
80 inputoutput, /* 225 degrees */
81 condition, /* 270 degrees */
82 subtract /* 315 degrees */
83 };
84
85 /*** Source code for Interpreter Functions ***/
86
87 /* Function main():
88 * Initializes data structures and environment, and iterates through
89 * each IP until termination. Also handles most common errors.
90 */
91 int main (int argc, char *argv[])
92 {
93 int i, x, y; /* Temporary variables */
94 FILE *infile; /* Input file */
95
96 if (argc < 2) /* Not enough arguments--don't know what to do */
97 {
98 fprintf (stderr, "Error:\n\t%s <Wierd Filename>\n", argv[0]);
99 exit (1);
100 }
101 infile = fopen (argv[1], "r");
102 if (infile == NULL) /* Bad input filename given */
103 {
104 fprintf (stderr, "Error: Invalid Wierd filename: \"%s\".\n",
105 argv[1]);
106 exit (2);
107 }
108
109 for (x=0;x<SIZE;++x) /* Clear the memoryspace */
110 for (y=0;y<SIZE;++y)
111 workspace[x][y] = '\000';
112
113 y = 1; /* Read the file into the memoryspace */
114 while (!feof (infile))
115 {
116 fscanf (infile, "%[^\n]", &workspace[y][1]);
117 fgetc (infile);
118 #ifdef DEBUG
119 printf ("%s\n", &workspace[y][1]);
120 #endif
121 ++y;
122 }
123 fclose (infile); /* Clean up file handles */
124 for (x=0;x<SIZE;++x) /* Convert nulls to spaces */
125 for (y=0;y<SIZE;++y)
126 if (workspace[x][y] == '\000')
127 workspace[x][y] = ' ';
128
129 /* Initialize the first IP */
130 list = (struct iplist *) malloc (sizeof (struct iplist));
131 list->x = list->y = list->dx = list->dy = 1;
132 list->s_top = 0;
133 list->next = list;
134 list->ipid = ++ipid;
135
136 /* Loop as long as the location is valid */
137 while (workspace[list->x][list->y] != ' ')
138 {
139 ip_killed = 0; /* Initialize the kill-flag */
140 #ifdef DEBUG
141 printf ("<%d>\t", list->ipid);
142 printf ("(%d,%d)\t", list->y, list->x);
143 for (i=0;i<list->s_top;++i)
144 printf ("[%d] ", list->stack[i]);
145 #endif
146 tmpx = list->dx; /* Save the current direction */
147 tmpy = list->dy; /* and change it */
148 i = getnextturn (list->x, list->y, &tmpx, &tmpy);
149 #ifdef DEBUG
150 printf ("\t\t%d\n", i);
151 #endif
152 if (i % 45) /* Invalid direction! */
153 printf ("\007ERROR!!\007\n");
154 else { /* Call the appropriate function */
155 i = function[i/45](&list);
156 if (i == -1) /* Out of IPs */
157 {
158 free (list);
159 return 0;
160 }
161 }
162 if (!ip_killed) /* Only update if it's the same IP */
163 {
164 list->x += list->dx = tmpx; /* Update location */
165 list->y += list->dy = tmpy;
166 list = list->next; /* Next IP */
167 }
168 }
169 #ifdef DEBUG
170 printf ("Program ungracefully terminated!\n");
171 #endif
172 return 0;
173 }
174
175 /* Function checkdir():
176 * Simple function to determine validity of location a given delta
177 * from the given location.
178 */
179 int checkdir (int x, int y, int dx, int dy)
180 {
181 return (workspace[x+dx][y+dy] != ' '); /* Only space is invalid */
182 }
183
184 /* Function rotate():
185 * Turns an IP the specified number of degrees (though only in 45-
186 * degree increments).
187 */
188 int rotate (int * xdir, int * ydir, int turn)
189 {
190 int i;
191
192 for (i=0;i<turn;i+=45) /* We only work in 45-degree increments */
193 turn45 (xdir, ydir);
194 return 0;
195 }
196
197 /* Function turn45():
198 * Rotates a dx,dy heading 45 degrees clockwise. Very unclean
199 * implementation, but it works for now. Once we expand beyond two
200 * dimensions, though, this will have to be heavily rewritten.
201 */
202 int turn45 (int * xdir, int * ydir)
203 {
204 if (*ydir == 1 && *xdir == -1 || *ydir == -1 && *xdir == 1)
205 *ydir = 0;
206 else if (*xdir == 1 && *ydir == 1 || *xdir == -1 && *ydir == -1)
207 *xdir = 0;
208 else if (*ydir)
209 *xdir -= *ydir;
210 else *ydir += *xdir;
211 return 0;
212 }
213
214 /* Function getnextturn():
215 * Checks the 7 of the 8 valid directions from the given point,
216 * choosing those 7 based on the IP delta. Returns the "leftmost"
217 * direction closest to "straight" that is available from the given
218 * location.
219 */
220 int getnextturn (int x, int y, int * dx, int * dy)
221 {
222 if (checkdir (x, y, *dx, *dy))
223 return 0;
224 rotate (dx, dy, 45);
225 if (checkdir (x, y, *dx, *dy))
226 return 45;
227 rotate (dx, dy, 270);
228 if (checkdir (x, y, *dx, *dy))
229 return 315;
230 rotate (dx, dy, 135);
231 if (checkdir (x, y, *dx, *dy))
232 return 90;
233 rotate (dx, dy, 180);
234 if (checkdir (x, y, *dx, *dy))
235 return 270;
236 rotate (dx, dy, 225);
237 if (checkdir (x, y, *dx, *dy))
238 return 135;
239 rotate (dx, dy, 90);
240 if (checkdir (x, y, *dx, *dy))
241 return 225;
242 return 180;
243 }
244
245 /* Function add_thread():
246 * Inserts a node on the circular linked list of IPs, and initializes
247 * the node as a new IP.
248 */
249 int add_thread (struct iplist * ip, int dx, int dy)
250 {
251 struct iplist *temp;
252 int i;
253
254 /* Create new node on list */
255 temp = (struct iplist *) malloc (sizeof (struct iplist));
256 temp->ipid = ++ipid; /* Give an identifier */
257 temp->next = ip->next; /* Insert into list */
258 temp->x = ip->x - dx; /* Initialize based on current IP */
259 temp->y = ip->y - dy;
260 temp->dx = - dx;
261 temp->dy = - dy;
262 temp->s_top = ip->s_top;
263 for (i=0;i<ip->s_top;++i)
264 temp->stack[i] = ip->stack[i];
265 ip->next = temp;
266 #ifdef DEBUG
267 printf ("Thread #%d created.\n", temp->ipid);
268 #endif
269 return 0;
270 }
271
272 /* Function kill_thread():
273 * Removes the current node from the circular linked list of IPs.
274 */
275 int kill_thread (struct iplist ** ip)
276 {
277 struct iplist *temp;
278 #ifdef DEBUG
279 int id;
280
281 id = (*ip)->ipid;
282 #endif
283 temp = *ip;
284 while (temp->next != *ip) /* Get IP before this one */
285 temp = temp->next;
286 temp->next = (*ip)->next; /* Point around the current IP */
287 free (*ip); /* Deallocate the IP */
288 *ip = temp; /* Return the previous one */
289 #ifdef DEBUG
290 printf ("Thread #%d destroyed, passing to #%d.\n", id, (*ip)->ipid);
291 #endif
292 return 0;
293 }
294
295 /* Function find_far():
296 * Called when the IP has no obvious place to go. Checks the region
297 * around (7x7 locations) the current IP location for a "closest
298 * point" based on the current location as well as the current IP
299 * direction.
300 */
301 int find_far (int x, int y, int dx, int dy, int **xcoors, int **ycoors)
302 {
303 int i, j, pts, xs[40], ys[40], ti, tj,
304 a[] = {2, 3, -2, -3, 0, 1, -1}; /* Order of precedence */
305
306 pts = 0;
307 for (i=0;i<7;++i) for (j=0;j<7;++j)
308 /* Scan along the array in two dimensions */
309 if (i < 4 || j < 4) /* If at least one index looks at {2,3} */
310 {
311 ti = dx>0?a[i]:-a[i]; /* Invert if a delta is */
312 tj = dy>0?a[j]:-a[j]; /* negative */
313 if (x>a[i] && y>a[j] &&
314 workspace[x+ti][y+tj] != ' ')
315 { /* If the location exists and isn't */
316 xs[pts] = x + ti; /* a space */
317 ys[pts] = y + tj; /* Add to list */
318 if (xs[pts] > 0 && ys[pts] > 0)
319 ++ pts;
320 }
321 }
322 *xcoors = (int *) malloc (sizeof (int) * pts);
323 *ycoors = (int *) malloc (sizeof (int) * pts);
324 for (i=0;i<pts;++i) /* Copy the list of candidates to where the */
325 { /* calling function suggests */
326 (*xcoors)[i] = xs[i];
327 (*ycoors)[i] = ys[i];
328 }
329 return (pts); /* Return the number of points found */
330 }
331
332 /*** Source Code for internal Interpreter Operations (called from the
333 function table only ***/
334
335 /* Function nop():
336 * No-operation.
337 */
338 int nop (struct iplist ** list)
339 {
340 return 0; /* Self-explanatory */
341 }
342
343 /* Function push1():
344 * Pushes a constant value 1 onto the IP's stack.
345 */
346 int push1 (struct iplist ** ip)
347 {
348 struct iplist *list = *ip;
349
350 list->stack[list->s_top++] = 1; /* Self-explanatory */
351 return 0;
352 }
353
354 /* Function condition():
355 * If the top of the IP's stack is zero, functions as nop().
356 * Otherwise, it reverses the direction of the IP.
357 */
358 int condition (struct iplist ** ip)
359 {
360 int i;
361 struct iplist *list = *ip;
362
363 /* Two coincident 90-degree turns spawns a new IP */
364 if (workspace[list->x-tmpx][list->y-tmpy] != ' ')
365 add_thread (list, tmpx, tmpy);
366 /* Otherwise, check top of the stack determines whether */
367 /* we continue or change direction */
368 else if (list->s_top && list->stack[--list->s_top])
369 {
370 list->x += tmpx;
371 list->y += tmpy;
372 i = tmpx; /* Reflect the IP */
373 tmpx = -tmpy;
374 tmpy = -i;
375 i = getnextturn (list->x, list->y, &tmpx, &tmpy);
376 #ifdef DEBUG
377 printf ("<%d>\t", list->ipid);
378 printf ("(%d,%d)\t", list->y, list->x);
379 for (i=0;i<list->s_top;++i)
380 printf ("[%d] ", list->stack[i]);
381 printf ("\t\t%d\n", i);
382 #endif
383 }
384 *ip = list; /* Fix the IP list in case the current thread changed */
385 return 0;
386 }
387
388 /* Function getput():
389 * If the top of the stack is zero, retrieves the byte stored at the
390 * coordinates specified on the stack. Otherwise, takes the element
391 * on the stack beneath the coordinates and stores the value at those
392 * coordinates.
393 */
394 int getput (struct iplist ** ip)
395 {
396 int xcoor, ycoor;
397 struct iplist *list = *ip;
398
399 if (list->s_top < 3) /* Not enough stack elements to do anything */
400 return 1;
401 if (list->stack[--list->s_top]) /* A non-zero is a "put" */
402 {
403 xcoor = list->stack[--list->s_top];
404 ycoor = list->stack[--list->s_top];
405 list->stack[list->s_top++] = workspace[xcoor][ycoor];
406 }
407 else { /* Otherwise it's a "get" */
408 xcoor = list->stack[--list->s_top];
409 ycoor = list->stack[--list->s_top];
410 workspace[xcoor][ycoor] = list->stack[--list->s_top];
411 }
412 return 0;
413 }
414
415 /* Function inputoutput():
416 * If the top of the stack is zero, gets a character from input.
417 * Otherwise, it prints the next character on the stack.
418 */
419 int inputoutput (struct iplist ** ip)
420 {
421 struct iplist *list = *ip;
422
423 if (list->s_top < 1) /* Nothing useful on the stack */
424 return 1;
425 if (list->stack[--list->s_top]) /* If it's nonzero, print the next */
426 putchar (list->stack[--list->s_top]);
427 /* Otherwise request a character */
428 else list->stack[list->s_top++] = getchar ();
429 return 0;
430 }
431
432 /* Function subtract():
433 * Subtracts the top two stack elements.
434 */
435 int subtract (struct iplist ** ip)
436 {
437 struct iplist *list = *ip;
438
439 if (list->s_top < 2) /* Can't subtract without two elements */
440 return 1;
441 list->stack[list->s_top - 2] -= list->stack[list->s_top - 1];
442 --list->s_top; /* Otherwise, subtract top from under and pop */
443 return 0;
444 }
445
446 /* Function terminus():
447 * Based on current environmental conditions, either sparks the IP
448 * across the gap, or kills the IP.
449 */
450 int terminus (struct iplist ** ip)
451 {
452 int i, j, k, *xlist, *ylist;
453 struct iplist *list = *ip;
454
455 /* Check for a line to spark to */
456 j = find_far (list->x, list->y, list->dx, list->dy, &xlist, &ylist);
457 #ifdef DEBUG
458 for (k=0;k<j;++k)
459 printf ("\t\t{%d,%d}\n", ylist[k], xlist[k]);
460 #endif
461 if (j < 3) /* Less than three means it's probably our */
462 { /* incoming path */
463 if (list->next == list)
464 return -1; /* so kill the thread */
465 kill_thread (&list);
466 ip_killed = 1;
467 }
468 else { /* Otherwise, we have valid locations */
469 list->x = xlist[0]; /* and they *should* be ordered */
470 list->y = ylist[0]; /* by preference */
471 i = getnextturn (list->x, list->y, &tmpx, &tmpy);
472 #ifdef DEBUG
473 printf ("==> %d choices available.\n", j);
474 printf ("<%d>\t", list->ipid);
475 printf ("(%d,%d)\t", list->y, list->x);
476 for (i=0;i<list->s_top;++i)
477 printf ("[%d] ", list->stack[i]);
478 printf ("\t\t%d\n", i);
479 #endif
480 }
481 *ip = list; /* Fix the list pointer in case it was changed */
482 return 0;
483 }