-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path1l_aoi.c
327 lines (275 loc) · 7.74 KB
/
1l_aoi.c
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
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/*
This file implements 1L_AOI language http://esolangs.org/wiki/1L_AOI
Specify -eu to use 1L_AOI_EU dialect. See comment for `if (!eu)` to learn differences between dialects.
This file is based on yoob implementaion of 1L_AOI, https://github.com/catseye/yoob/blob/master/src/lang/OneLAOIState.java
Differences from yoob implementation:
- in yoob tape is infinite in both directions, but here only nonnegative indexes allowed and size is limited to 4096 cells (cell index = 0..4095)
author: stasoid; released to public domain
*/
#include <malloc.h>
#include <memory.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
//#include <conio.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/stat.h>
#include <assert.h>
// display "warning C4706: assignment within conditional expression" at warning level 3 in Visual Studio
#pragma warning(3: 4706)
#define byte unsigned char
#define bool char
#define false 0
#define true 1
#define elif else if
//#define assert(e) ((e) ? __noop : __debugbreak())
#define max(a,b) ((a)>(b)?(a):(b))
char* usage = "Usage: 1l_aoi [-eu] filename";
bool eu = false;
char* readfile(const char* fname, int* _size);
void readcode(char* str, int len);
void doIO();
bool step();
void debugprint();
int main(int argc, char* argv[])
{
//getc(stdin);
//putchar('A');putchar('B');
//getch();
//return 0;
char* filename = 0;
if(argc < 2) { puts(usage); return 1; }
if(argv[1][0] == '-')
{
if(strcmp(argv[1], "-eu") != 0) { puts(usage); return 1; }
if(argc < 3) { puts(usage); return 1; }
eu = true;
filename = argv[2];
}
else
filename = argv[1];
int len=0;
char* str = readfile(filename, &len);
if(!str) { printf("cannot read file"); return 1; }
readcode(str, len);
while(step());
debugprint();
}
int width, height;
char* code;
// zero-based, x grows right, y grows down
int x=0,y=1;
typedef enum{left,right,up,down} edir;
edir dir = right;
#define tapesize 4096
byte tape[tapesize] = {0, 1};
int cellindex = 2;
void debugprint()
{
fprintf(stderr, "\ntape:[%d,%d,%d] index:%d", tape[0], tape[1], tape[2], cellindex);
}
#define xyok(x,y) ( (x) >= 0 && (x) < width && (y) >= 0 && (y) < height )
char get_ahead_left()
{
int _x=x, _y=y;
switch(dir)
{
case left: _x--, _y++; break;
case right: _x++, _y--; break;
case up: _x--, _y--; break;
case down: _x++, _y++; break;
}
return xyok(_x,_y) ? code[_x+_y*width] : ' ';
}
char get_ahead_right()
{
int _x=x, _y=y;
switch(dir)
{
case left: _x--, _y--; break;
case right: _x++, _y++; break;
case up: _x++, _y--; break;
case down: _x--, _y++; break;
}
return xyok(_x,_y) ? code[_x+_y*width] : ' ';
}
#define DX(dir) ((dir) == left ? -1 : (dir) == right ? 1 : 0)
#define DY(dir) ((dir) == up ? -1 : (dir) == down ? 1 : 0)
#define opposite(dir) ((dir) == left ? right : (dir) == right ? left : (dir) == up ? down : up) // turn 180 degrees
edir rotate(edir _dir, int angle)
{
assert(angle == 90 || angle == -90 || angle == 180);
if(angle == 180) return opposite(_dir);
bool clockwise = angle == 90; // turn right
if (_dir == right) _dir = clockwise ? down : up;
elif(_dir == left) _dir = clockwise ? up : down;
elif(_dir == down) _dir = clockwise ? left : right;
elif(_dir == up) _dir = clockwise ? right : left;
else assert(0 && "Invalid direction");
return _dir;
}
bool step()
{
char c = code[x+y*width];
if(c == '+')
{
/* If the Command Pointer passes through a + sign then the following is evaluated: */
if(dir == up)
{
// Up -- Increase MP Cell by one
if(cellindex == 1)
doIO();
else
tape[cellindex]++;
}
elif(dir == down)
{
// Down -- Move MP Right
if(cellindex == tapesize-1) { puts("attempt at increasing cellindex past tapesize-1"); exit(1); }
cellindex++;
}
elif(dir == right)
{
// Right -- Move MP Left
if(cellindex == 0) { puts("attempt at decreasing cellindex below 0"); exit(1); }
cellindex--;
}
else
{
// Left -- Decrease MP Cell by one
if(cellindex == 1)
doIO();
else
tape[cellindex]--;
}
}
/*
* If the Command Pointer passes by a + sign, the effect is determined as follows.
* Normally, the Command Pointer will turn away from the +.
* If however, the Command Pointer would have been turned left, and the
* the Memory Pointer cell is zero, no turn occurs and the Command Pointer proceeds straight.
* (The + sign must be diagonally opposite the
* point at which the CP is required to turn.)
*/
// Check the two diagonally-in-front-of squares for +'s
bool rotateRight = get_ahead_left() == '+';
bool rotateLeft = get_ahead_right() == '+';
byte b = tape[cellindex];
if (!eu)
{
/*
* Here's where 1L_AOI and 1L_AOI_EU differ. In 1L_AOI, deflection is
* conditional, full stop.
*/
rotateRight = rotateRight && (b!=0);
rotateLeft = rotateLeft && (b!=0);
if(rotateLeft && rotateRight)
dir = rotate(dir, 180);
elif(rotateRight)
dir = rotate(dir, 90);
elif(rotateLeft)
dir = rotate(dir, -90);
}
else
{
/*
* In 1L_AOI_EU, deflection to the right is conditional on zero (turns right if current cell is 0),
* deflection to the left is conditional on non-zero (turns left if current cell is nonzero).
*/
rotateRight = rotateRight && (b==0);
rotateLeft = rotateLeft && (b!=0);
if(rotateLeft && rotateRight)
dir = rotate(dir, 180); // never happens because cell cannot be zero and nonzero simultaneously
elif(rotateRight)
dir = rotate(dir, 90);
elif(rotateLeft)
dir = rotate(dir, -90);
}
x += DX(dir);
y += DY(dir);
return xyok(x,y);
}
/*
* I/O is the same as 2L:
* "The two leftmost tape locations, called TL0 (Tape Location 0) and TL1 (Tape Location 1)
* respectively, are significant. TL1 doesn't actually hold a value, it merely causes an I/O
* operation if you attempt to increment or decrement it. If the value at TL0 is 0, and you
* attempt to change the value of TL1, a character will be read from input into TL0. If TL0
* is not 0, and you attempt to change the value of TL1, a character will be outputted from
* the value of TL0."
*/
void doIO()
{
if(!tape[0]) tape[0] = getchar();
else putchar(tape[0]);
}
int getlinelen(char* str, int len)
{
int i;
for(i=0; i<len && str[i]!='\n'; i++);
// if we searched entire str and did not find any newlines (i==len) then number of chars in the line is len (entire str)
// otherwise it is i+1 (\n included)
return i==len ? len : i+1;
}
int get_newline_size(char* line, int linelen)
{
if(linelen >= 2 && line[linelen-1] == '\n' && line[linelen-2] == '\r') return 2;
if(linelen >= 1 && line[linelen-1] == '\n') return 1;
return 0;
}
// this should work with files containing null bytes
// readfile adds null byte, but readcode does not rely on that
void readcode(char* str, int len)
{
int totallen = len;
char* line = str;
width = height = 0;
// calc width/height (max line length and number of lines)
while(len > 0)
{
int linelen = getlinelen(line, len);
int crlf = get_newline_size(line, linelen);
width = max(width, linelen - crlf);
height++;
line += linelen;
len -= linelen;
}
len = totallen;
if(len>0 && str[len-1]=='\n') height++;
code = calloc(width*height, 1);
line = str;
int y=0;
while(len > 0)
{
int linelen = getlinelen(line, len);
for(int x=0; x < linelen; x++)
code[x+y*width] = line[x];
y++;
line += linelen;
len -= linelen;
}
if(height < 2) { puts("file should have at least 2 lines"); exit(1); }
}
int fsize(const char *filename)
{
struct stat st;
if (stat(filename, &st) == 0)
return st.st_size;
return -1;
}
// adds null byte, but also optionally returns size
char* readfile(const char* fname, int* _size)
{
int size;
char* buf;
FILE* f = fopen(fname, "rb");
if (!f) return 0;
size = fsize(fname);
buf = (char*)malloc(size + 1);
fread(buf, 1, size, f);
buf[size] = 0;
fclose(f);
if(_size) *_size = size;
return buf;
}