3 #include <sys/lunaix.h>
9 #define check(statement) \
12 if ((err = (statement)) < 0) { \
13 syslog(2, #statement " failed: %d", err); \
23 #define MAZE_WIDTH TTY_WIDTH-1
24 #define MAZE_HEIGHT TTY_HEIGHT
26 #define BUFFER_SIZE 1024
44 void get_rand(unsigned int *r, unsigned int max) {
54 typedef struct player_t {
59 typedef struct write_cmd {
62 char data[MAZE_WIDTH+1];
65 typedef struct node_t {
70 typedef struct stack_t {
73 }road_list_t, cue_list_t;
75 road_list_t road_list;
79 for (size_t i = 0; i < 1000; i++)
81 road_list.node[i].x = 0;
82 road_list.node[i].y = 0;
86 for (size_t i = 0; i < 1000; i++)
88 cue_list.node[i].x = 0;
89 cue_list.node[i].y = 0;
94 int insert_road_list(node_t n) {
95 if (road_list.length>=1000)
101 get_rand(&r, road_list.length);
102 for (size_t i = road_list.length; i > r; i--)
104 road_list.node[i] = road_list.node[i-1];
106 road_list.node[r] = n;
111 int push_road_list(node_t node) {
112 if (road_list.length>=1000)
116 road_list.node[road_list.length] = node;
121 node_t pop_road_list() {
122 node_t n={.x = 0, .y = 0};
123 if (road_list.length==0)
127 n = road_list.node[road_list.length-1];
128 road_list.node[road_list.length-1].x = 0;
129 road_list.node[road_list.length-1].y = 0;
134 int push_cue_list(node_t node) {
135 if (cue_list.length>=1000)
139 cue_list.node[cue_list.length] = node;
144 node_t pop_cue_list() {
145 node_t n={.x = 0, .y = 0};
146 if (cue_list.length==0)
150 n = cue_list.node[cue_list.length-1];
151 cue_list.node[cue_list.length-1].x = 0;
152 cue_list.node[cue_list.length-1].y = 0;
157 int iswall(node_t n) {
163 return n.x%2==0 || n.y%2==0;
167 // no matter it is marked as '-'
168 int isroad(node_t n) {
169 if (n.x<=0 || n.y<=0 || n.x>=MAZE_WIDTH-1 || n.y>=MAZE_HEIGHT-1)
178 void generate_rand_road_node(node_t *n)
180 get_rand((unsigned int *)&n->x, MAZE_WIDTH);
181 get_rand((unsigned int *)&n->y, MAZE_HEIGHT);
189 if (n->x<=(MAZE_WIDTH/2))
201 if (n->y<=(MAZE_HEIGHT/2))
212 char maze[MAZE_HEIGHT][MAZE_WIDTH];
213 char visited[MAZE_HEIGHT][MAZE_WIDTH];
215 void pick_near_road_to_list(node_t current_node) {
219 picked_node.x = current_node.x;
220 picked_node.y = current_node.y-2;
221 if (isroad(picked_node) && maze[picked_node.y][picked_node.x]!=ROAD)
223 insert_road_list(picked_node);
227 picked_node.x = current_node.x+2;
228 picked_node.y = current_node.y;
229 if (isroad(picked_node) && maze[picked_node.y][picked_node.x]!=ROAD)
231 insert_road_list(picked_node);
235 picked_node.x = current_node.x;
236 picked_node.y = current_node.y+2;
237 if (isroad(picked_node) && maze[picked_node.y][picked_node.x]!=ROAD)
239 insert_road_list(picked_node);
243 picked_node.x = current_node.x-2;
244 picked_node.y = current_node.y;
245 if (isroad(picked_node) && maze[picked_node.y][picked_node.x]!=ROAD)
247 insert_road_list(picked_node);
251 node_t pick_near_road(node_t current_node) {
255 picked_node.x = current_node.x;
256 picked_node.y = current_node.y-2;
257 if (isroad(picked_node) && maze[picked_node.y][picked_node.x]==ROAD)
263 picked_node.x = current_node.x-2;
264 picked_node.y = current_node.y;
265 if (isroad(picked_node) && maze[picked_node.y][picked_node.x]==ROAD)
271 picked_node.x = current_node.x;
272 picked_node.y = current_node.y+2;
273 if (isroad(picked_node) && maze[picked_node.y][picked_node.x]==ROAD)
279 picked_node.x = current_node.x+2;
280 picked_node.y = current_node.y;
281 if (isroad(picked_node) && maze[picked_node.y][picked_node.x]==ROAD)
290 void break_wall(node_t n1, node_t n2)
294 maze[(n1.y+n2.y+1)/2][n1.x]=ROAD;
298 maze[n1.y][(n1.x+n2.x+1)/2]=ROAD;
305 wcmd.data[MAZE_WIDTH] = '\0';
307 for (size_t j = 0; j < MAZE_HEIGHT; j++)
309 for (size_t i = 0; i < MAZE_WIDTH; i++)
311 wcmd.data[i] = maze[j][i];
314 write(fd, &wcmd, sizeof(write_cmd));
318 void refresh_line(int y){
322 wcmd.data[MAZE_WIDTH] = '\0';
324 for (size_t i = 0; i < MAZE_WIDTH; i++)
326 wcmd.data[i] = maze[y][i];
329 write(fd, &wcmd, sizeof(write_cmd));
337 for (size_t i = 0; i < MAZE_HEIGHT; i++)
339 for (size_t j = 0; j < MAZE_WIDTH; j++)
345 rand_fd = open("/dev/rand", O_RDONLY);
347 generate_rand_road_node(&start_node);
349 maze[start_node.y][start_node.x] = ROAD;
351 pick_near_road_to_list(start_node);
353 while (road_list.length>0)
355 node_t n = pop_road_list();
356 maze[n.y][n.x] = ROAD;
357 node_t n2 = pick_near_road(n);
358 maze[n2.y][n2.x] = ROAD;
360 pick_near_road_to_list(n);
365 maze[MAZE_HEIGHT-2][MAZE_WIDTH-2] = FLAG;
367 refresh_line(MAZE_HEIGHT-2);
372 set_termios(int fd) {
375 check(tcgetattr(fd, &term));
377 term.c_lflag = IEXTEN | ISIG | ECHO | ECHOE | ECHONL;
378 term.c_cc[VERASE] = 0x7f;
380 check(tcsetattr(fd, 0, &term));
386 set_termios_end(int fd) {
389 check(tcgetattr(fd, &term));
391 term.c_lflag = ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHONL;
392 term.c_cc[VERASE] = 0x7f;
394 check(tcsetattr(fd, 0, &term));
402 if (maze[player.y-1][player.x]!='#')
405 maze[player.y][player.x] = 'P';
406 maze[player.y+1][player.x] = ' ';
408 refresh_line(player.y);
409 refresh_line(player.y+1);
413 if (maze[player.y][player.x+1]!='#')
416 maze[player.y][player.x] = 'P';
417 maze[player.y][player.x-1] = ' ';
419 refresh_line(player.y);
423 if (maze[player.y+1][player.x]!='#')
426 maze[player.y][player.x] = 'P';
427 maze[player.y-1][player.x] = ' ';
429 refresh_line(player.y);
430 refresh_line(player.y-1);
434 if (maze[player.y][player.x-1]!='#')
437 maze[player.y][player.x] = 'P';
438 maze[player.y][player.x+1] = ' ';
440 refresh_line(player.y);
443 void visit_node(node_t current_node){
447 picked_node.x = current_node.x;
448 picked_node.y = current_node.y-1;
449 if (maze[picked_node.y][picked_node.x]!=PLAYER && maze[picked_node.y][picked_node.x]!=WALL && visited[picked_node.y][picked_node.x]!=VISITED)
451 push_road_list(picked_node);
455 picked_node.x = current_node.x+1;
456 picked_node.y = current_node.y;
457 if (maze[picked_node.y][picked_node.x]!=PLAYER && maze[picked_node.y][picked_node.x]!=WALL && visited[picked_node.y][picked_node.x]!=VISITED)
459 push_road_list(picked_node);
463 picked_node.x = current_node.x;
464 picked_node.y = current_node.y+1;
465 if (maze[picked_node.y][picked_node.x]!=PLAYER && maze[picked_node.y][picked_node.x]!=WALL && visited[picked_node.y][picked_node.x]!=VISITED)
467 push_road_list(picked_node);
471 picked_node.x = current_node.x-1;
472 picked_node.y = current_node.y;
473 if (maze[picked_node.y][picked_node.x]!=PLAYER && maze[picked_node.y][picked_node.x]!=WALL && visited[picked_node.y][picked_node.x]!=VISITED)
475 push_road_list(picked_node);
479 int is_near_node(node_t n1, node_t n2){
480 if (n1.x==n2.x && (n1.y-n2.y==1 || n1.y-n2.y==-1))
484 else if (n1.y==n2.y && (n1.x-n2.x==1 || n1.x-n2.x==-1))
488 else if (n1.x==n2.x && n1.y==n2.y)
499 for (size_t i = 0; i < MAZE_HEIGHT; i++)
501 for (size_t j = 0; j < MAZE_WIDTH; j++)
507 node_t node = player;
508 node_t cue_node = player;
509 push_road_list(node);
510 push_cue_list(cue_node);
511 while (road_list.length>0 && maze[node.y][node.x]!=FLAG)
513 node = pop_road_list();
514 cue_node = pop_cue_list();
515 while (!is_near_node(node, cue_node) && cue_node.x!=0)
517 if (maze[cue_node.y][cue_node.x] != PLAYER)
519 maze[cue_node.y][cue_node.x] = ROAD;
521 refresh_line(cue_node.y);
522 cue_node = pop_cue_list();
526 push_cue_list(cue_node);
529 if (maze[node.y][node.x]!=FLAG && visited[node.y][node.x]!=VISITED)
531 if (maze[node.y][node.x]!=PLAYER)
533 maze[node.y][node.x] = CUE;
536 visited[node.y][node.x] = VISITED;
540 refresh_line(node.y);
545 main(int argc, char* argv[])
547 fd = open("/dev/ttyG0", FO_RDWR);
548 check(set_termios(fd));
557 read(fd, &action, 1);
583 check(set_termios_end(fd));