RSokoban 0.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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