Wed Apr 17 01:05:42 PDT 2002
[netwalk.git] / netwalk.e
blobf2475672b811d4316e21cc58350fa0b80412db29
1 --TODO: similar code: get_neighbour, is_surrounded. need TUPLEs?
2 class NETWALK
3 inherit DIR_CONSTANT; SDL_CONSTANT; COLOR_TABLE; CONFIG
4 creation make
5 feature
6 tile_server_top : INTEGER is 1
7 tile_server_bottom : INTEGER is 2
8 tile_normal : INTEGER is 3
9 tile_terminal : INTEGER is 4
11 board : ARRAY2[TILE]
12 width : INTEGER
13 height : INTEGER
14 servertopi : INTEGER is
16 Result := width // 2
17 end
18 servertopj : INTEGER is
20 Result := height // 2 + 1
21 end
23 font : TTF_FONT is
25 Result := config.bigfont
26 end
28 win_image : IMAGE is
29 once
30 !!Result.make
31 Result.render_string("Well Done", font, white)
32 end
34 allow_wrap : BOOLEAN
35 difficulty : INTEGER
37 seed : INTEGER
39 make is
41 !!rand.make
42 ext_init
43 connected_pipe_color := green
44 disconnected_pipe_color := darkred
45 connected_terminal_color := cyan
46 disconnected_terminal_color := darkpurple
47 width := 10
48 height := 9
49 main_loop
50 end
52 new_game is
54 rand.with_seed(seed)
55 !!board.make(1, width, 1, height)
56 generate_board
57 preprocess_board
58 scramble_board
59 game_state := state_playing
60 if difficulty > 0 then
61 allow_wrap := True
62 else
63 allow_wrap := False
64 end
65 end
67 state_none : INTEGER is 0
68 state_playing : INTEGER is 1
69 state_victory : INTEGER is 2
70 state_quit : INTEGER is 3
71 game_state : INTEGER
73 main_loop is
74 local
75 e : EVENT
77 from
78 until game_state = state_quit
79 loop
80 seed := seed + 1
81 blank_screen
82 draw_border
83 if game_state = state_playing then
84 draw_board
85 if check_connections then
86 game_state := state_victory
87 end
88 end
89 if game_state = state_victory then
90 draw_board
91 win_image.blit(50, 400)
92 end
93 ext_update_screen
94 e := poll_event
95 if e /= Void then
96 handle_event(e)
97 end
98 end
99 end
101 handle_event(e : EVENT) is
103 inspect e.type
104 when sdl_keydown then
105 inspect e.i1
106 when sdlk_escape then
107 game_state := state_quit
108 when sdlk_f3 then
109 difficulty := difficulty + 1
110 if difficulty > 1 then
111 difficulty := 0
113 when sdlk_f2 then
114 new_game
115 else
117 when sdl_mousebuttondown then
118 handle_mbdown(e)
119 else
123 handle_mbdown(e : EVENT) is
124 local
125 i, j : INTEGER
127 if game_state = state_playing then
128 i := e.x // cellwidth
129 j := e.y // cellheight
130 if on_board(i, j) then
131 if e.i1 = 1 then
132 rotateccw(i, j)
133 else
134 rotatecw(i, j)
140 rotatecw(i, j : INTEGER) is
141 local
142 t : TILE
143 dir : INTEGER
144 bak : BOOLEAN
146 t := board.item(i, j)
147 if t = server_top or else t = server_bottom then
148 bak := server_top.neighbour.item(1)
149 server_top.neighbour.put(server_bottom.neighbour.item(4), 1)
150 server_bottom.neighbour.put(server_bottom.neighbour.item(3), 4)
151 server_bottom.neighbour.put(server_bottom.neighbour.item(2), 3)
152 server_bottom.neighbour.put(bak, 2)
153 elseif t /= Void then
154 bak := t.neighbour.item(4)
155 from dir := 4
156 until dir = 1
157 loop
158 t.neighbour.put(t.neighbour.item(dir - 1), dir)
159 dir := dir - 1
161 t.neighbour.put(bak, dir)
165 rotateccw(i, j : INTEGER) is
166 local
167 t : TILE
168 dir : INTEGER
169 bak : BOOLEAN
171 t := board.item(i, j)
172 if t = server_top or else t = server_bottom then
173 bak := server_top.neighbour.item(1)
174 server_top.neighbour.put(server_bottom.neighbour.item(2), 1)
175 server_bottom.neighbour.put(server_bottom.neighbour.item(3), 2)
176 server_bottom.neighbour.put(server_bottom.neighbour.item(4), 3)
177 server_bottom.neighbour.put(bak, 4)
178 elseif t /= Void then
179 bak := t.neighbour.item(1)
180 from dir := 1
181 until dir = 4
182 loop
183 t.neighbour.put(t.neighbour.item(dir + 1), dir)
184 dir := dir + 1
186 t.neighbour.put(bak, dir)
190 server_top, server_bottom : TILE
192 preprocess_board is
193 local
194 i, j : INTEGER
195 t : TILE
197 from i := 1
198 until i > width
199 loop
200 from j := 1
201 until j > height
202 loop
203 t := board.item(i, j)
204 if t /= Void then
205 t.count_neighbours
207 j := j + 1
209 i := i + 1
213 draw_board is
214 local
215 i, j : INTEGER
217 from i := 1
218 until i > width
219 loop
220 from j := 1
221 until j > height
222 loop
223 draw_tile(board.item(i, j))
224 j := j + 1
226 i := i + 1
230 draw_border is
231 local
232 i : INTEGER
234 from i := 1
235 until i > width + 1
236 loop
237 fill_rect(i * cellwidth, cellheight, 1, height * cellheight, blue)
238 i := i + 1
241 from i := 1
242 until i > height + 1
243 loop
244 fill_rect(cellwidth, i * cellheight, width * cellwidth, 1, blue)
245 i := i + 1
249 cellwidth : INTEGER is 32
250 cellheight : INTEGER is 32
251 uppipex : INTEGER is 13
252 uppipew : INTEGER is 6
253 uppipeh : INTEGER is 19
254 leftpipey : INTEGER is 13
255 leftpipew : INTEGER is 19
256 leftpipeh : INTEGER is 6
258 check_connections : BOOLEAN is
259 local
260 check_list : LINKED_LIST[TILE]
261 i, j : INTEGER
262 dir : INTEGER
263 t, t2 : TILE
265 from i := 1
266 until i > width
267 loop
268 from j := 1
269 until j > height
270 loop
271 t := board.item(i, j)
272 if t /= Void then
273 t.disconnect
275 j := j + 1
277 i := i + 1
280 !!check_list.make
281 check_list.add_last(server_top)
282 check_list.add_last(server_bottom)
283 server_top.connect
284 server_bottom.connect
286 from
287 until check_list.is_empty
288 loop
289 t := check_list.first
290 check_list.remove_first
291 from dir := 1
292 until dir > 4
293 loop
294 if t.neighbour.item(dir) then
295 t2 := get_neighbour(t, dir)
296 if t2 /= Void and then
297 t2.neighbour.item(dir_opposite(dir)) and then
298 not t2.is_connected then
299 t2.connect
300 check_list.add_last(t2)
303 dir := dir + 1
307 --victory check
308 Result := True
309 from i := 1
310 until i > width or else not Result
311 loop
312 from j := 1
313 until j > height or else not Result
314 loop
315 t := board.item(i, j)
316 if t /= Void and then not t.is_connected then
317 Result := False
319 j := j + 1
321 i := i + 1
325 maybe_wrapx(i : INTEGER) : INTEGER is
327 Result := i
328 if allow_wrap then
329 if i < 1 then
330 Result := i + width
331 elseif i > width then
332 Result := i - width
337 maybe_wrapy(i : INTEGER) : INTEGER is
339 Result := i
340 if allow_wrap then
341 if i < 1 then
342 Result := i + height
343 elseif i > height then
344 Result := i - height
349 get_neighbour(t : TILE; dir : INTEGER) : TILE is
350 local
351 x, y : INTEGER
352 x1, y1 : INTEGER
354 if dir = dir_up then
355 y1 := -1
356 elseif dir = dir_down then
357 y1 := 1
360 if dir = dir_left then
361 x1 := -1
362 elseif dir = dir_right then
363 x1 := 1
365 x := maybe_wrapx(t.x + x1)
366 y := maybe_wrapy(t.y + y1)
367 if on_board(x, y) then
368 Result := board.item(x, y)
372 on_board(x, y : INTEGER) : BOOLEAN is
374 Result := x >= 1 and then x <= width
375 and then y >= 1 and then y <= height
378 connected_pipe_color : COLOR
379 disconnected_pipe_color : COLOR
380 connected_terminal_color : COLOR
381 disconnected_terminal_color : COLOR
383 draw_tile(tile : TILE) is
384 local
385 x : INTEGER
386 y : INTEGER
387 c, c2 : COLOR
389 if tile /= Void then
390 x := tile.x * cellwidth
391 y := tile.y * cellheight
392 if tile.is_connected then
393 c := connected_pipe_color
394 c2 := connected_terminal_color
395 else
396 c := disconnected_pipe_color
397 c2 := disconnected_terminal_color
400 if tile.neighbour.item(dir_up) then
401 fill_rect(x + uppipex, y, uppipew, uppipeh, c)
403 if tile.neighbour.item(dir_left) then
404 fill_rect(x, y + leftpipey, leftpipew, leftpipeh, c)
406 if tile.neighbour.item(dir_right) then
407 fill_rect(x + uppipex, y + leftpipey, leftpipew, leftpipeh, c)
409 if tile.neighbour.item(dir_down) then
410 fill_rect(x + uppipex, y + leftpipey, uppipew, uppipeh, c)
413 inspect tile.type
414 when tile_server_top then
415 fill_rect(x + 5, y + 5, cellwidth - 10, cellheight - 5, blue)
416 when tile_server_bottom then
417 fill_rect(x + 5, y, cellwidth - 10, cellheight - 5, blue)
418 when tile_terminal then
419 fill_rect(x + 8, y + 8, 16, 16, c2)
420 else
426 ext_fill_rect(x, y, w, h : INTEGER; c : INTEGER) is
427 external "C"
430 wrap_flag : BOOLEAN
432 open_list : LINKED_LIST[TILE]
434 rand : STD_RAND
436 generate_board is
437 local
438 i : INTEGER
439 t : TILE
441 --place server
442 !!server_bottom.make_server_bottom
443 place_tile(server_bottom, servertopi, servertopj + 1)
444 !!server_top.make_server_top
445 place_tile(server_top, servertopi, servertopj)
447 --generate maze
448 !!open_list.make
449 open_list.add_last(server_top)
450 open_list.add_last(server_bottom)
452 from
453 until open_list.is_empty
454 loop
455 rand.next
456 i := rand.last_integer(open_list.count)
457 t := open_list @ i
458 rand.next
459 i := rand.last_integer(4)
460 try_extend(t, i)
464 best : INTEGER
466 scramble_board is
467 local
468 i, j : INTEGER
470 best := 0
471 from i := 1
472 until i > width
473 loop
474 from j := 1
475 until j > height
476 loop
477 if board.item(i, j) /= server_top then
478 rand.next
479 inspect rand.last_integer(4)
480 when 1 then
481 rotateccw(i, j)
482 best := best + 1
483 when 2 then
484 rotatecw(i, j)
485 best := best + 1
486 when 3 then
487 rotatecw(i, j)
488 rotatecw(i, j)
489 best := best + 2
490 else
493 j := j + 1
495 i := i + 1
499 try_extend(t : TILE; dir : INTEGER) is
500 local
501 x, y : INTEGER
502 x1, y1 : INTEGER
503 t2 : TILE
504 i : INTEGER
506 if dir = dir_up then
507 y1 := -1
508 elseif dir = dir_down then
509 y1 := 1
512 if dir = dir_left then
513 x1 := -1
514 elseif dir = dir_right then
515 x1 := 1
518 x := maybe_wrapx(t.x + x1)
519 y := maybe_wrapy(t.y + y1)
521 if on_board(x, y) then
522 t2 := board.item(x, y)
523 if t = server_top and then (dir = dir_left or else dir = dir_right) then
524 elseif t2 /= Void then
525 else
526 !!t2.make
527 place_tile(t2, x, y)
528 t.neighbour.put(True, dir)
529 t2.neighbour.put(True, dir_opposite(dir))
530 open_list.add_last(t2)
532 from i := open_list.lower
533 until i > open_list.upper
534 loop
535 if is_surrounded(open_list @ i) then
536 open_list.remove(i)
537 else
538 i := i + 1
545 is_surrounded(t : TILE) : BOOLEAN is
546 local
547 dir : INTEGER
548 x, y : INTEGER
549 x1, y1 : INTEGER
550 count : INTEGER
552 Result := True
553 from dir := 1
554 until dir > 4
555 loop
556 if t.neighbour.item(dir) then
557 count := count + 1
559 y1 := 0
560 if dir = dir_up then
561 y1 := -1
562 elseif dir = dir_down then
563 y1 := 1
566 x1 := 0
567 if dir = dir_left then
568 x1 := -1
569 elseif dir = dir_right then
570 x1 := 1
573 x := maybe_wrapx(t.x + x1)
574 y := maybe_wrapy(t.y + y1)
576 if on_board(x, y) then
577 if board.item(x, y) = Void then
578 if t = server_top then
579 if dir /= dir_left and then dir /= dir_right then
580 Result := False
582 else
583 Result := False
587 dir := dir + 1
589 if count >= 3 then
590 Result := True
594 place_tile(tile : TILE; x, y : INTEGER) is
596 tile.put_xy(x, y)
597 board.put(tile, x, y)
600 poll_event : EVENT is
601 local
602 em : EVENTMAKER
604 Result := ext_poll_event(em)
607 ext_init is
608 external "C"
611 ext_poll_event(em : EVENTMAKER) : EVENT is
612 external "C" alias "ext_poll_event"
615 ext_update_screen is
616 external "C"
619 fill_rect(x, y, w, h : INTEGER; c : COLOR) is
621 --ext_fill_rect(x + offsetx, y + offsety, w, h, c.to_integer)
622 ext_fill_rect(x, y, w, h, c.to_integer)
625 blank_screen is
627 fill_rect(0, 0, 640, 480, black)