RSokoban 0.71
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +674 -0
- data/README.rdoc +47 -0
- data/TODO +34 -0
- data/bin/rsokoban +10 -0
- data/data/microban.xsb +1838 -0
- data/data/original.xsb +1497 -0
- data/data/test.xsb +30 -0
- data/lib/rsokoban/crate.rb +16 -0
- data/lib/rsokoban/exception.rb +7 -0
- data/lib/rsokoban/game.rb +105 -0
- data/lib/rsokoban/level.rb +269 -0
- data/lib/rsokoban/level_loader.rb +58 -0
- data/lib/rsokoban/level_set.rb +31 -0
- data/lib/rsokoban/man.rb +17 -0
- data/lib/rsokoban/moveable.rb +22 -0
- data/lib/rsokoban/option.rb +93 -0
- data/lib/rsokoban/position.rb +24 -0
- data/lib/rsokoban/raw_level.rb +16 -0
- data/lib/rsokoban/storage.rb +14 -0
- data/lib/rsokoban/ui/console.rb +107 -0
- data/lib/rsokoban/ui/curses_console.rb +123 -0
- data/lib/rsokoban/ui/ui.rb +44 -0
- data/lib/rsokoban.rb +29 -0
- data/test/original.xsb +1497 -0
- data/test/tc_level.rb +773 -0
- data/test/tc_level_loader.rb +88 -0
- data/test/tc_level_set.rb +42 -0
- data/test/tc_man.rb +55 -0
- data/test/tc_moveable.rb +41 -0
- data/test/tc_position.rb +75 -0
- data/test/tc_raw_level.rb +35 -0
- data/test/test.rb +16 -0
- data/test/test_file1.xsb +9 -0
- data/test/test_file2.xsb +49 -0
- data/test/ui/tc_console.rb +75 -0
- metadata +102 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
|
2
|
+
module RSokoban::UI
|
3
|
+
|
4
|
+
# I am a portable console for the user interface.
|
5
|
+
# In addition to what BaseUI want from me, I offer the user
|
6
|
+
# an help feature.
|
7
|
+
# I assume 24 lines height.
|
8
|
+
class Console < BaseUI
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super()
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_action(type, level, message)
|
15
|
+
@level_title = message if type == 'START'
|
16
|
+
message = 'OK move 0' if type == 'START'
|
17
|
+
display level, message
|
18
|
+
if type == 'DISPLAY' or type == 'START'
|
19
|
+
askPlayer
|
20
|
+
else
|
21
|
+
# assuming type == 'WIN'
|
22
|
+
askForNextLevel
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def display level, message
|
29
|
+
blankConsole = "\n" * 24 # assuming a console window of 24 lines height
|
30
|
+
puts blankConsole
|
31
|
+
puts @level_title
|
32
|
+
puts "--------------------"
|
33
|
+
puts message
|
34
|
+
puts ''
|
35
|
+
level.each {|line| puts line }
|
36
|
+
puts ''
|
37
|
+
end
|
38
|
+
|
39
|
+
def askForNextLevel
|
40
|
+
printf "Play next level ? "
|
41
|
+
line = readline.chomp
|
42
|
+
if ['yes', 'ye', 'y', 'YES', 'YE', 'Y'].include?(line)
|
43
|
+
:next
|
44
|
+
else
|
45
|
+
:quit
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def askPlayer
|
50
|
+
printf "Your choice ? "
|
51
|
+
line = readline.chomp
|
52
|
+
response = parse line
|
53
|
+
if response.nil?
|
54
|
+
puts "Error : #{line}"
|
55
|
+
askPlayer
|
56
|
+
elsif response == :help
|
57
|
+
displayHelp
|
58
|
+
askPlayer
|
59
|
+
else
|
60
|
+
response
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse str
|
65
|
+
case str
|
66
|
+
when 'quit', 'up', 'down', 'right', 'left', 'retry', 'help'
|
67
|
+
str.to_sym
|
68
|
+
when 'z'
|
69
|
+
:up
|
70
|
+
when 's'
|
71
|
+
:down
|
72
|
+
when 'q'
|
73
|
+
:left
|
74
|
+
when 'd'
|
75
|
+
:right
|
76
|
+
when '1'..'999'
|
77
|
+
str.to_i
|
78
|
+
when /\.xsb$/
|
79
|
+
str
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def displayHelp
|
84
|
+
help=<<EOS
|
85
|
+
------------------------------
|
86
|
+
General commands :
|
87
|
+
|
88
|
+
quit : Quit game
|
89
|
+
help : Display this screen
|
90
|
+
retry : Restart level
|
91
|
+
1 to 999 : Play this level
|
92
|
+
file.xsb : Load this set of levels
|
93
|
+
|
94
|
+
How to move :
|
95
|
+
|
96
|
+
up (or z) : Move up
|
97
|
+
down (or s) : Move down
|
98
|
+
left (or q) : Move left
|
99
|
+
right (or d) : Move right
|
100
|
+
------------------------------
|
101
|
+
EOS
|
102
|
+
puts help
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
module RSokoban::UI
|
4
|
+
|
5
|
+
# I am a console user interface using curses library.
|
6
|
+
# I assume 24 lines height.
|
7
|
+
class CursesConsole < BaseUI
|
8
|
+
|
9
|
+
@@TITLE_LINE = 0
|
10
|
+
@@MOVES_LINE = 1
|
11
|
+
@@STATUS_LINE = 2
|
12
|
+
@@PICTURE_LINE = 4
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
super()
|
16
|
+
init_screen
|
17
|
+
ensure
|
18
|
+
Curses.close_screen
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_action(type, level, message)
|
22
|
+
if type == 'START' or type == 'END_OF_SET'
|
23
|
+
@level_title = message
|
24
|
+
message = 'OK move 0'
|
25
|
+
Curses.clear
|
26
|
+
end
|
27
|
+
if type == 'DISPLAY' or type == 'START' or type == 'END_OF_SET'
|
28
|
+
ask_player level, message
|
29
|
+
else
|
30
|
+
# assuming type == 'WIN'
|
31
|
+
askForNextLevel level, message
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def init_screen
|
38
|
+
Curses.noecho # do not show typed keys
|
39
|
+
Curses.init_screen
|
40
|
+
Curses.stdscr.keypad(true) # enable arrow keys
|
41
|
+
Curses.curs_set 0
|
42
|
+
end
|
43
|
+
|
44
|
+
def display level, message
|
45
|
+
write @@TITLE_LINE, 0, @level_title
|
46
|
+
move_index = message =~ /\d+/
|
47
|
+
write @@MOVES_LINE, 0, 'moves : ' + message[move_index..-1] if move_index
|
48
|
+
write @@STATUS_LINE, 0, 'arrows=move (q)uit (r)etry (l)oad level/set'
|
49
|
+
line_num = @@PICTURE_LINE
|
50
|
+
level.each {|line|
|
51
|
+
write line_num, 0, line
|
52
|
+
line_num += 1
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def write(line, column, text)
|
57
|
+
Curses.setpos(line, column)
|
58
|
+
Curses.addstr(text);
|
59
|
+
end
|
60
|
+
|
61
|
+
def askForNextLevel level, message
|
62
|
+
display level, message
|
63
|
+
write @@STATUS_LINE, 0, "LEVEL COMPLETED ! Play next level ? (yes, no) "
|
64
|
+
case Curses.getch
|
65
|
+
when ?n, ?N then :quit
|
66
|
+
when ?y, ?Y then :next
|
67
|
+
else
|
68
|
+
askForNextLevel level, message
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def ask_player level, message
|
73
|
+
display level, message
|
74
|
+
response = get_player_input
|
75
|
+
if response.nil?
|
76
|
+
ask_player level, message
|
77
|
+
else
|
78
|
+
response
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_player_input
|
83
|
+
case Curses.getch
|
84
|
+
when Curses::Key::UP then :up
|
85
|
+
when Curses::Key::DOWN then :down
|
86
|
+
when Curses::Key::LEFT then :left
|
87
|
+
when Curses::Key::RIGHT then :right
|
88
|
+
when ?q, ?Q then :quit
|
89
|
+
when ?r, ?R then :retry
|
90
|
+
when ?l, ?L then ask_level_or_set
|
91
|
+
else
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def ask_level_or_set
|
97
|
+
Curses.curs_set 1
|
98
|
+
Curses.echo
|
99
|
+
Curses.clear
|
100
|
+
help=<<EOS
|
101
|
+
------------------------------------------------------------
|
102
|
+
To load a level from this set, type its number.
|
103
|
+
To load a set of level, type its name (with .xsb).
|
104
|
+
Int 1 : Don't forget to hit return.
|
105
|
+
Int 2 : type any letter to cancel and restart previous level
|
106
|
+
------------------------------------------------------------
|
107
|
+
|
108
|
+
EOS
|
109
|
+
write 0, 0, help
|
110
|
+
str = Curses.getstr
|
111
|
+
Curses.curs_set 0
|
112
|
+
Curses.noecho
|
113
|
+
case str
|
114
|
+
when '1'..'999' then str.to_i
|
115
|
+
when /\.xsb$/ then str
|
116
|
+
else
|
117
|
+
:retry
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module RSokoban
|
2
|
+
|
3
|
+
# Module dedicated to user interfaces.
|
4
|
+
module UI
|
5
|
+
|
6
|
+
# Every concrete UI should inherits from me.
|
7
|
+
class BaseUI
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@level_title = ''
|
11
|
+
end
|
12
|
+
|
13
|
+
# Based on things found in the arguments, I display the game
|
14
|
+
# to the user. Then he can tell what it want to do. Whatever
|
15
|
+
# my childs permit the user to do, they can only return one
|
16
|
+
# of the following actions.
|
17
|
+
#
|
18
|
+
# List of action I must be able to parse and return :
|
19
|
+
# :quit to quit game
|
20
|
+
# :next to load and play next level
|
21
|
+
# :retry to restart the current level
|
22
|
+
# :up, :down, :left, :right to move the man
|
23
|
+
# a number to load this level number
|
24
|
+
# an .xsb filename to load the set with this name
|
25
|
+
#
|
26
|
+
# @param ['START'|'DISPLAY'|'WIN'] type the type of message
|
27
|
+
# @param [Array<String>] level the picture of the level
|
28
|
+
# @param [String] message a message to be displayed. See Level#move
|
29
|
+
# to learn more about the message format and content.
|
30
|
+
# @return [Object] the user's action
|
31
|
+
# @since 0.71
|
32
|
+
# @todo write some examples
|
33
|
+
# @todo action diserves its own class
|
34
|
+
# @todo picture diserves its own class
|
35
|
+
# @todo document better +type+
|
36
|
+
def get_action(type, level, message)
|
37
|
+
raise "Please implement me !"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/rsokoban.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rsokoban/level"
|
2
|
+
require "rsokoban/level_loader"
|
3
|
+
require "rsokoban/exception"
|
4
|
+
require "rsokoban/position"
|
5
|
+
require "rsokoban/man"
|
6
|
+
require "rsokoban/crate"
|
7
|
+
require "rsokoban/storage"
|
8
|
+
require "rsokoban/game"
|
9
|
+
require "rsokoban/option"
|
10
|
+
require "rsokoban/level_set"
|
11
|
+
require "rsokoban/raw_level"
|
12
|
+
require "rsokoban/ui/ui"
|
13
|
+
|
14
|
+
# I am the main module of the game.
|
15
|
+
module RSokoban
|
16
|
+
# Version of the program
|
17
|
+
VERSION = '0.71'
|
18
|
+
|
19
|
+
# Game elements.
|
20
|
+
# Those constants are used intensively.
|
21
|
+
MAN = '@'
|
22
|
+
FLOOR = ' '
|
23
|
+
CRATE = '$'
|
24
|
+
STORAGE = '.'
|
25
|
+
WALL = '#'
|
26
|
+
MAN_ON_STORAGE = '+'
|
27
|
+
CRATE_ON_STORAGE = '*'
|
28
|
+
|
29
|
+
end
|