1 --TODO: similar code: get_neighbour, is_surrounded. need TUPLEs?
3 inherit DIR_CONSTANT
; SDL_CONSTANT
; COLOR_TABLE
; CONFIG
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
13 default_width
: INTEGER is 10
14 default_height
: INTEGER is 9
15 min_width
: INTEGER is 5
16 max_width
: INTEGER is 15
17 min_height
: INTEGER is 4
18 max_height
: INTEGER is 13
22 servertopi
: INTEGER is
26 servertopj
: INTEGER is
28 Result := height
// 2 + 1
33 Result := config
.bigfont
36 mainfont
: TTF_FONT
is
38 Result := config
.mainfont
44 Result.render_string("Well Done", font
, white
)
52 new_game_button
: BUTTON
53 options_button
: BUTTON
56 options_window
: OPTIONS_WINDOW
58 widget_list
: LINKED_LIST
[WIDGET
]
60 add_widget(w
: WIDGET
) is
62 widget_list
.add_last(w
)
73 connected_pipe_color
:= green
74 disconnected_pipe_color
:= darkred
75 connected_terminal_color
:= cyan
76 disconnected_terminal_color
:= darkpurple
77 width
:= default_width
78 height
:= default_height
80 move_image
.render_string("moves: " + move_count
.to_string
, mainfont
, white
)
82 best_image
.render_string("par: " + best
.to_string
, mainfont
, white
)
84 !!new_game_button
.make("New Game")
85 new_game_button
.put_geometry(550, 20, 80, 20)
86 !COMMAND_NEW_GAME
!c
.make(Current)
87 new_game_button
.put_command(c
, new_game_button
.signal_activate
)
88 add_widget(new_game_button
)
90 !!options_button
.make("Options")
91 options_button
.put_geometry(550, 60, 80, 20)
92 !COMMAND_OPTIONS
!c
.make(Current)
93 options_button
.put_command(c
, options_button
.signal_activate
)
94 add_widget(options_button
)
96 !!quit_button
.make("Quit")
97 quit_button
.put_geometry(550, 100, 80, 20)
98 !COMMAND_QUIT
!c
.make(Current)
99 quit_button
.put_command(c
, quit_button
.signal_activate
)
100 add_widget(quit_button
)
107 make_options_window
is
111 !!options_window
.make
112 !COMMAND_OPTIONS_OK
!c
.make(Current)
113 options_window
.put_command(c
, options_window
.signal_activate
)
114 !COMMAND_OPTIONS_CANCEL
!c
.make(Current)
115 options_window
.put_command(c
, options_window
.signal_cancel
)
120 options_window_showing
122 options_window_showing
:= False
127 options_window_showing
132 options_window_showing
:= False
133 allow_wrap
:= options_window
.wrap_cb
.value
134 s
:= options_window
.width_tb
.string
137 if i
< min_width
then
139 elseif i
> max_width
then
147 s
:= options_window
.height_tb
.string
150 if i
< min_height
then
152 elseif i
> max_height
then
164 !!board
.make(1, width
, 1, height
)
171 game_state
:= state_playing
176 options_window_showing
:= True
177 options_window
.wrap_cb
.put_value(allow_wrap
)
178 options_window
.width_tb
.put_string(width
.to_string
)
179 options_window
.height_tb
.put_string(height
.to_string
)
182 state_none
: INTEGER is 0
183 state_playing
: INTEGER is 1
184 state_victory
: INTEGER is 2
185 state_quit
: INTEGER is 3
187 options_window_showing
: BOOLEAN
194 until game_state
= state_quit
198 widget_list
.do_all(agent {WIDGET
}.update
)
200 if game_state
= state_playing
then
202 if check_connections
then
203 game_state
:= state_victory
206 if game_state
= state_victory
then
208 win_image
.blit(50, 400)
211 best_image
.blit(10, 440)
212 move_image
.blit(10, 460)
214 if options_window_showing
then
215 options_window
.update
221 if options_window_showing
then
222 options_window
.process_event(e
)
232 game_state
:= state_quit
235 handle_event(e
: EVENT
) is
238 when sdl_keydown
then
244 when sdl_mousebuttondown
then
252 handle_mbdown(e
: EVENT
) is
255 it
: ITERATOR
[WIDGET
]
257 it
:= widget_list
.get_new_iterator
261 if it
.item
.contains(e
.x
, e
.y
) then
262 it
.item
.process_event(e
)
266 if game_state
= state_playing
then
267 i
:= e
.x
// cellwidth
268 j
:= e
.y
// cellheight
269 if on_board(i
, j
) then
286 move_image
.render_string("moves: " + move_count
.to_string
, mainfont
, white
)
291 move_count
:= move_count
+ 1
293 move_image
.render_string("moves: " + move_count
.to_string
, mainfont
, white
)
299 best_image
.render_string("par: " + best
.to_string
, mainfont
, white
)
302 rotatecw(i
, j
: INTEGER) is
308 t
:= board
.item(i
, j
)
310 if t
= server_top
or else t
= server_bottom
then
311 bak
:= server_top
.neighbour
.item(1)
312 server_top
.neighbour
.put(server_bottom
.neighbour
.item(4), 1)
313 server_bottom
.neighbour
.put(server_bottom
.neighbour
.item(3), 4)
314 server_bottom
.neighbour
.put(server_bottom
.neighbour
.item(2), 3)
315 server_bottom
.neighbour
.put(bak
, 2)
317 bak
:= t
.neighbour
.item(4)
321 t
.neighbour
.put(t
.neighbour
.item(dir
- 1), dir
)
324 t
.neighbour
.put(bak
, dir
)
330 rotateccw(i
, j
: INTEGER) is
336 t
:= board
.item(i
, j
)
338 if t
= server_top
or else t
= server_bottom
then
339 bak
:= server_top
.neighbour
.item(1)
340 server_top
.neighbour
.put(server_bottom
.neighbour
.item(2), 1)
341 server_bottom
.neighbour
.put(server_bottom
.neighbour
.item(3), 2)
342 server_bottom
.neighbour
.put(server_bottom
.neighbour
.item(4), 3)
343 server_bottom
.neighbour
.put(bak
, 4)
345 bak
:= t
.neighbour
.item(1)
349 t
.neighbour
.put(t
.neighbour
.item(dir
+ 1), dir
)
352 t
.neighbour
.put(bak
, dir
)
358 server_top
, server_bottom
: TILE
371 t
:= board
.item(i
, j
)
391 draw_tile(board
.item(i
, j
))
405 fill_rect(i
* cellwidth
, cellheight
, 1, height
* cellheight
, blue
)
412 fill_rect(cellwidth
, i
* cellheight
, width
* cellwidth
, 1, blue
)
417 cellwidth
: INTEGER is 32
418 cellheight
: INTEGER is 32
419 uppipex
: INTEGER is 13
420 uppipew
: INTEGER is 6
421 uppipeh
: INTEGER is 19
422 leftpipey
: INTEGER is 13
423 leftpipew
: INTEGER is 19
424 leftpipeh
: INTEGER is 6
426 check_connections
: BOOLEAN is
428 check_list
: LINKED_LIST
[TILE
]
439 t
:= board
.item(i
, j
)
449 check_list
.add_last(server_top
)
450 check_list
.add_last(server_bottom
)
452 server_bottom
.connect
455 until check_list
.is_empty
457 t
:= check_list
.first
458 check_list
.remove_first
462 if t
.neighbour
.item(dir
) then
463 t2
:= get_neighbour(t
, dir
)
464 if t2
/= Void
and then
465 t2
.neighbour
.item(dir_opposite(dir
)) and then
466 not t2
.is_connected
then
468 check_list
.add_last(t2
)
478 until i
> width
or else not Result
481 until j
> height
or else not Result
483 t
:= board
.item(i
, j
)
484 if t
/= Void
and then not t
.is_connected
then
493 maybe_wrapx(i
: INTEGER) : INTEGER is
499 elseif i
> width
then
505 maybe_wrapy(i
: INTEGER) : INTEGER is
511 elseif i
> height
then
517 get_neighbour(t
: TILE
; dir
: INTEGER) : TILE
is
524 elseif dir
= dir_down
then
528 if dir
= dir_left
then
530 elseif dir
= dir_right
then
533 x
:= maybe_wrapx(t
.x
+ x1
)
534 y
:= maybe_wrapy(t
.y
+ y1
)
535 if on_board(x
, y
) then
536 Result := board
.item(x
, y
)
540 on_board(x
, y
: INTEGER) : BOOLEAN is
542 Result := x
>= 1 and then x
<= width
543 and then y
>= 1 and then y
<= height
546 connected_pipe_color
: COLOR
547 disconnected_pipe_color
: COLOR
548 connected_terminal_color
: COLOR
549 disconnected_terminal_color
: COLOR
551 draw_tile(tile
: TILE
) is
558 x
:= tile
.x
* cellwidth
559 y
:= tile
.y
* cellheight
560 if tile
.is_connected
then
561 c
:= connected_pipe_color
562 c2
:= connected_terminal_color
564 c
:= disconnected_pipe_color
565 c2
:= disconnected_terminal_color
568 if tile
.neighbour
.item(dir_up
) then
569 fill_rect(x
+ uppipex
, y
, uppipew
, uppipeh
, c
)
571 if tile
.neighbour
.item(dir_left
) then
572 fill_rect(x
, y
+ leftpipey
, leftpipew
, leftpipeh
, c
)
574 if tile
.neighbour
.item(dir_right
) then
575 fill_rect(x
+ uppipex
, y
+ leftpipey
, leftpipew
, leftpipeh
, c
)
577 if tile
.neighbour
.item(dir_down
) then
578 fill_rect(x
+ uppipex
, y
+ leftpipey
, uppipew
, uppipeh
, c
)
582 when tile_server_top
then
583 fill_rect(x
+ 7, y
+ 7, cellwidth
- 12, cellheight
- 6, blue
)
584 when tile_server_bottom
then
585 fill_rect(x
+ 7, y
, cellwidth
- 12, cellheight
- 6, blue
)
586 when tile_terminal
then
587 fill_rect(x
+ 8, y
+ 8, 16, 16, c2
)
594 ext_fill_rect(x
, y
, w
, h
: INTEGER; c
: INTEGER) is
600 open_list
: LINKED_LIST
[TILE
]
610 !!server_bottom
.make_server_bottom
611 place_tile(server_bottom
, servertopi
, servertopj
+ 1)
612 !!server_top
.make_server_top
613 place_tile(server_top
, servertopi
, servertopj
)
617 open_list
.add_last(server_top
)
618 open_list
.add_last(server_bottom
)
621 until open_list
.is_empty
624 i
:= rand
.last_integer(open_list
.count
)
627 i
:= rand
.last_integer(4)
645 if board
.item(i
, j
) /= server_top
then
647 inspect rand
.last_integer(4)
658 --don't count reflections
659 if board
.item(i
, j
) = server_bottom
and then
660 server_top
.neighbour
.item(dir_up
) = server_bottom
.neighbour
.item(dir_down
) and then
661 server_bottom
.neighbour
.item(dir_left
) = server_bottom
.neighbour
.item(dir_right
) then
664 elseif board
.item(i
, j
).is_symmetric
then
676 try_extend(t
: TILE
; dir
: INTEGER) is
685 elseif dir
= dir_down
then
689 if dir
= dir_left
then
691 elseif dir
= dir_right
then
695 x
:= maybe_wrapx(t
.x
+ x1
)
696 y
:= maybe_wrapy(t
.y
+ y1
)
698 if on_board(x
, y
) then
699 t2
:= board
.item(x
, y
)
700 if t
= server_top
and then (dir
= dir_left
or else dir
= dir_right
) then
701 elseif t2
/= Void
then
705 t
.neighbour
.put(True, dir
)
706 t2
.neighbour
.put(True, dir_opposite(dir
))
707 open_list
.add_last(t2
)
709 from i
:= open_list
.lower
710 until i
> open_list
.upper
712 if is_surrounded(open_list @ i
) then
722 is_surrounded(t
: TILE
) : BOOLEAN is
733 if t
.neighbour
.item(dir
) then
739 elseif dir
= dir_down
then
744 if dir
= dir_left
then
746 elseif dir
= dir_right
then
750 x
:= maybe_wrapx(t
.x
+ x1
)
751 y
:= maybe_wrapy(t
.y
+ y1
)
753 if on_board(x
, y
) then
754 if board
.item(x
, y
) = Void
then
755 if t
= server_top
then
756 if dir
/= dir_left
and then dir
/= dir_right
then
771 place_tile(tile
: TILE
; x
, y
: INTEGER) is
774 board
.put(tile
, x
, y
)
777 poll_event
: EVENT
is
781 Result := ext_poll_event(em
)
788 ext_poll_event(em
: EVENTMAKER
) : EVENT
is
789 external "C" alias "ext_poll_event"
796 fill_rect(x
, y
, w
, h
: INTEGER; c
: COLOR
) is
798 --ext_fill_rect(x + offsetx, y + offsety, w, h, c.to_integer)
799 ext_fill_rect(x
, y
, w
, h
, c
.to_integer
)
804 fill_rect(0, 0, 640, 480, black
)