sokoban.rb 0.0.1

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.
data/.README.swp ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ */**/*.swp
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1,3 @@
1
+ rvm use ruby-1.9.1-p376
2
+ #it is possible to switch to use ruby 1.9.2 with ffi-opengl - if changing boolean switch: SHOW_FFI
3
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in sokoban.gemspec
4
+ gemspec
data/README ADDED
@@ -0,0 +1,39 @@
1
+
2
+ about using opengl with different versions of Ruby:
3
+ #######################################
4
+ #ruby 1.9.1 :
5
+ #gem : ruby-opengl
6
+ #
7
+ #if working with ruby 1.9.1-p376 + gem: ruby-opengl :
8
+ #read: http://rubygamedev.wordpress.com/2010/04/16/ruby-opengl-on-ruby-1-9/
9
+ #
10
+ # ruby 1.9.2 :
11
+ # gem: ffi-opengl
12
+ ########################################
13
+
14
+
15
+
16
+
17
+ 1.to play: run bin/sokoban
18
+ 2.
19
+ keys:
20
+ ----
21
+ as arrows:
22
+ ##u##
23
+ #hjk#
24
+
25
+ quit : press esc or q
26
+
27
+
28
+ next to implement:
29
+ -----------------
30
+ 1.console game
31
+ 2.console game with colors
32
+ 3.testing
33
+ 4.using ruby 1.9.2 with gosu opengl
34
+ 5.add optional prespective - user camera (fps view)
35
+ 6.moving project to mvc stracture
36
+ 7.draw only require cells
37
+
38
+ done:
39
+ use displaylist for faster drawing
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
Binary file
Binary file
data/bin/.sokoban.swp ADDED
Binary file
@@ -0,0 +1,266 @@
1
+
2
+ #require "sokoban"
3
+
4
+ def draw( g )
5
+ screen = "Level #{g.level} - #{g.moves} moves\n\n" + g.display
6
+ screen.gsub("\n", "\r\n")
7
+ end
8
+
9
+ system "stty raw -echo"
10
+
11
+ game = Sokoban.new
12
+
13
+ loop do
14
+ system "clear"
15
+ puts draw(game)
16
+
17
+ if game.level_solved?
18
+ puts "\r\nLevel solved. Nice Work!\r\n"
19
+ sleep 3
20
+ game.load_level
21
+
22
+ break if game.over?
23
+ end
24
+
25
+ case STDIN.getc
26
+ when ?Q, ?\C-c
27
+ break
28
+ when ?S
29
+ game.save
30
+ when ?L
31
+ game = Sokoban.load if test ?e, "sokoban_saved_game.yaml"
32
+ when ?R
33
+ game.restart_level
34
+ when ?U
35
+ game.undo
36
+ when ?j, ?j
37
+ game.move_left
38
+ when ?k, ?K
39
+ game.move_right
40
+ when ?m, ?m
41
+ game.move_down
42
+ when ?i, ?I
43
+ game.move_up
44
+ end
45
+ end
46
+
47
+ if game.over?
48
+ system "clear"
49
+ puts "\r\nYou've solved all the levels Puzzle Master!!!\r\n\r\n"
50
+ end
51
+
52
+ END { system "stty -raw echo" }
53
+
54
+ #!/usr/bin/env ruby
55
+
56
+ require "yaml"
57
+
58
+ class Sokoban
59
+ WALL = "#"
60
+ OPEN_FLOOR = " "
61
+
62
+ MAN = "@"
63
+ CRATE = "o"
64
+
65
+ STORAGE = "."
66
+ MAN_ON_STORAGE = "+"
67
+ CRATE_ON_STORAGE = "*"
68
+
69
+ MAX_UNDO = 10
70
+
71
+ PATH = File.expand_path(File.dirname(__FILE__))
72
+
73
+ attr_reader :level, :moves
74
+
75
+ def self.load( file = File.join(PATH, "sokoban_saved_game.yaml") )
76
+ game = nil
77
+
78
+ File.open file do |f|
79
+ game = YAML.load(f)
80
+ end
81
+
82
+ game ||= Sokoban.new
83
+ game
84
+ end
85
+
86
+ def initialize( file = File.join(PATH, "sokoban_levels.txt") )
87
+ @level_file = file
88
+
89
+ @board = [ ]
90
+ @level = 0
91
+ @over = false
92
+
93
+ @undos = [ ]
94
+ @moves = 0
95
+
96
+ load_level
97
+ end
98
+
99
+ def can_move_down?( ) can_move? :down end
100
+ def can_move_left?( ) can_move? :left end
101
+ def can_move_right?( ) can_move? :right end
102
+ def can_move_up?( ) can_move? :up end
103
+
104
+ def display
105
+ @board.inject("") { |dis, row| dis + row.join + "\n" }
106
+ end
107
+
108
+ def level_solved?
109
+ @board.each_with_index do |row, y|
110
+ row.each_with_index do |cell, x|
111
+ return false if cell == CRATE
112
+ end
113
+ end
114
+ true
115
+ end
116
+
117
+ def load_level( level = @level += 1, file = @level_file )
118
+ loaded = false
119
+
120
+ File.open file do |f|
121
+ count = 0
122
+ while lvl = f.gets("")
123
+ count += 1
124
+ if count == level
125
+ @board = [ ]
126
+ lvl.chomp!
127
+ lvl.each_line { |e| @board << e.chomp.split("") }
128
+ loaded = true
129
+ break
130
+ end
131
+ end
132
+ end
133
+
134
+ if loaded
135
+ @undos = [ ]
136
+ @moves = 0
137
+ else
138
+ @over = true
139
+ end
140
+
141
+ loaded
142
+ end
143
+
144
+ def move_down( ) move :down end
145
+ def move_left( ) move :left end
146
+ def move_right( ) move :right end
147
+ def move_up( ) move :up end
148
+
149
+ def over?
150
+ @over
151
+ end
152
+
153
+ def restart_level
154
+ load_level @level
155
+ end
156
+
157
+ def save( file = File.join(PATH, "sokoban_saved_game.yaml") )
158
+ File.open(file, "w") do |f|
159
+ f << YAML.dump(self)
160
+ end
161
+ end
162
+
163
+ def undo
164
+ if @undos.size > 0
165
+ @board = @undos.pop
166
+ @moves -= 1
167
+ end
168
+ end
169
+
170
+ private
171
+
172
+ def can_move?( dir )
173
+ x, y = where_am_i
174
+ case dir
175
+ when :down
176
+ first = @board[y + 1][x]
177
+ second = y < @board.size - 2 ? @board[y + 2][x] : nil
178
+ when :left
179
+ first = @board[y][x - 1]
180
+ second = x >= 2 ? @board[y][x - 2] : nil
181
+ when :right
182
+ first = @board[y][x + 1]
183
+ second = x < @board[y].size - 2 ? @board[y][x + 2] : nil
184
+ when :up
185
+ first = @board[y - 1][x]
186
+ second = y >= 2 ? @board[y - 2][x] : nil
187
+ end
188
+
189
+ if first == OPEN_FLOOR or first == STORAGE
190
+ true
191
+ elsif not second.nil? and
192
+ (first == CRATE or first == CRATE_ON_STORAGE) and
193
+ (second == OPEN_FLOOR or second == STORAGE)
194
+ true
195
+ else
196
+ false
197
+ end
198
+ end
199
+
200
+ def move( dir )
201
+ return false unless can_move? dir
202
+
203
+ @undos << Marshal.load(Marshal.dump(@board))
204
+ @undos.shift if @undos.size > MAX_UNDO
205
+ @moves += 1
206
+
207
+ x, y = where_am_i
208
+ case dir
209
+ when :down
210
+ if @board[y + 1][x] == CRATE or @board[y + 1][x] == CRATE_ON_STORAGE
211
+ move_crate x, y + 1, x, y + 2
212
+ end
213
+ move_man x, y, x, y + 1
214
+ when :left
215
+ if @board[y][x - 1] == CRATE or @board[y][x - 1] == CRATE_ON_STORAGE
216
+ move_crate x - 1, y, x - 2, y
217
+ end
218
+ move_man x, y, x - 1, y
219
+ when :right
220
+ if @board[y][x + 1] == CRATE or @board[y][x + 1] == CRATE_ON_STORAGE
221
+ move_crate x + 1, y, x + 2, y
222
+ end
223
+ move_man x, y, x + 1, y
224
+ when :up
225
+ if @board[y - 1][x] == CRATE or @board[y - 1][x] == CRATE_ON_STORAGE
226
+ move_crate x, y - 1, x, y - 2
227
+ end
228
+ move_man x, y, x, y - 1
229
+ end
230
+ true
231
+ end
232
+
233
+ def move_crate( from_x, from_y, to_x, to_y )
234
+ if @board[to_y][to_x] == STORAGE
235
+ @board[to_y][to_x] = CRATE_ON_STORAGE
236
+ else
237
+ @board[to_y][to_x] = CRATE
238
+ end
239
+ if @board[from_y][from_x] == CRATE_ON_STORAGE
240
+ @board[from_y][from_x] = STORAGE
241
+ else
242
+ @board[from_y][from_x] = OPEN_FLOOR
243
+ end
244
+ end
245
+
246
+ def move_man( from_x, from_y, to_x, to_y )
247
+ if @board[to_y][to_x] == STORAGE
248
+ @board[to_y][to_x] = MAN_ON_STORAGE
249
+ else
250
+ @board[to_y][to_x] = MAN
251
+ end
252
+ if @board[from_y][from_x] == MAN_ON_STORAGE
253
+ @board[from_y][from_x] = STORAGE
254
+ else
255
+ @board[from_y][from_x] = OPEN_FLOOR
256
+ end
257
+ end
258
+
259
+ def where_am_i
260
+ @board.each_with_index do |row, y|
261
+ row.each_with_index do |cell, x|
262
+ return x, y if cell == MAN or cell == MAN_ON_STORAGE
263
+ end
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,236 @@
1
+
2
+ require "opengl"
3
+ require "glut"
4
+
5
+ #require "sokoban"
6
+ require File.dirname(__FILE__) + '/../lib/sokoban'
7
+
8
+ PATH = File.expand_path(File.dirname(__FILE__))
9
+
10
+ def init
11
+ GL.Light GL::LIGHT0, GL::AMBIENT, [0.0, 0.0, 0.0, 1.0]
12
+ GL.Light GL::LIGHT0, GL::DIFFUSE, [1.0, 1.0, 1.0, 1.0]
13
+ GL.Light GL::LIGHT0, GL::POSITION, [0.0, 3.0, 3.0, 0.0]
14
+ GL.LightModel GL::LIGHT_MODEL_AMBIENT, [0.2, 0.2, 0.2, 1.0]
15
+ GL.LightModel GL::LIGHT_MODEL_LOCAL_VIEWER, [0.0]
16
+
17
+ GL.FrontFace GL::CW
18
+ GL.Enable GL::LIGHTING
19
+ GL.Enable GL::LIGHT0
20
+ GL.Enable GL::AUTO_NORMAL
21
+ GL.Enable GL::NORMALIZE
22
+ GL.Enable GL::DEPTH_TEST
23
+ GL.DepthFunc GL::LESS
24
+ end
25
+
26
+ def render_man
27
+ GL.Material GL::FRONT, GL::AMBIENT, [0.0, 0.0, 0.0, 1.0]
28
+ GL.Material GL::FRONT, GL::DIFFUSE, [0.5, 0.0, 0.0, 1.0]
29
+ GL.Material GL::FRONT, GL::SPECULAR, [0.7, 0.6, 0.6, 1.0]
30
+ GL.Material GL::FRONT, GL::SHININESS, 0.25 * 128.0
31
+
32
+ GLUT.SolidSphere 0.5, 16, 16
33
+ end
34
+
35
+ def render_crate
36
+ GL.Material GL::FRONT, GL::AMBIENT, [0.19125, 0.0735, 0.0225, 1.0]
37
+ GL.Material GL::FRONT, GL::DIFFUSE, [0.7038, 0.27048, 0.0828, 1.0]
38
+ GL.Material GL::FRONT, GL::SPECULAR, [0.256777, 0.137622, 0.086014, 1.0]
39
+ GL.Material GL::FRONT, GL::SHININESS, 0.1 * 128.0
40
+
41
+ GL.PushMatrix
42
+ GL.Scale 0.9, 0.9, 0.9
43
+ GL.Translate 0.0, 0.0, 0.45
44
+
45
+ GLUT.SolidCube 1.0
46
+ GL.PopMatrix
47
+ end
48
+
49
+ def render_stored_crate
50
+ GL.Material GL::FRONT, GL::AMBIENT, [0.25, 0.20725, 0.20725, 1.0]
51
+ GL.Material GL::FRONT, GL::DIFFUSE, [1.0, 0.829, 0.829, 1.0]
52
+ GL.Material GL::FRONT, GL::SPECULAR, [0.296648, 0.296648, 0.296648, 1.0]
53
+ GL.Material GL::FRONT, GL::SHININESS, 0.088 * 128.0
54
+
55
+ GL.PushMatrix
56
+ GL.Scale 0.9, 0.9, 0.9
57
+ GL.Translate 0.0, 0.0, 0.45
58
+
59
+ GLUT.SolidCube 1.0
60
+ GL.PopMatrix
61
+ end
62
+
63
+ def render_open_floor
64
+ GL.Material GL::FRONT, GL::AMBIENT, [0.05, 0.05, 0.05, 1.0]
65
+ GL.Material GL::FRONT, GL::DIFFUSE, [0.5, 0.5, 0.5, 1.0]
66
+ GL.Material GL::FRONT, GL::SPECULAR, [0.7, 0.7, 0.7, 1.0]
67
+ GL.Material GL::FRONT, GL::SHININESS, 0.078125 * 128.0
68
+
69
+ GL.PushMatrix
70
+ GL.Scale 0.9, 0.9, 0.1
71
+ GL.Translate 0.0, 0.0, -0.05
72
+
73
+ GLUT.SolidCube 1.0
74
+ GL.PopMatrix
75
+
76
+ GL.Material GL::FRONT, GL::AMBIENT, [0.05375, 0.05, 0.06625, 1.0]
77
+ GL.Material GL::FRONT, GL::DIFFUSE, [0.18275, 0.17, 0.22525, 1.0]
78
+ GL.Material GL::FRONT, GL::SPECULAR, [0.332741, 0.328634, 0.346435, 1.0]
79
+ GL.Material GL::FRONT, GL::SHININESS, 0.3 * 128.0
80
+
81
+ GL.PushMatrix
82
+ GL.Scale 1.0, 1.0, 0.1
83
+ GL.Translate 0.0, 0.0, -0.1
84
+
85
+ GLUT.SolidCube 1.0
86
+ GL.PopMatrix
87
+ end
88
+
89
+ def render_storage
90
+ GL.Material GL::FRONT, GL::AMBIENT, [0.05, 0.05, 0.0, 1.0]
91
+ GL.Material GL::FRONT, GL::DIFFUSE, [0.5, 0.5, 0.4, 1.0]
92
+ GL.Material GL::FRONT, GL::SPECULAR, [0.7, 0.7, 0.04, 1.0]
93
+ GL.Material GL::FRONT, GL::SHININESS, 0.078125 * 128.0
94
+
95
+ GL.PushMatrix
96
+ GL.Scale 0.9, 0.9, 0.1
97
+ GL.Translate 0.0, 0.0, -0.05
98
+
99
+ GLUT.SolidCube 1.0
100
+ GL.PopMatrix
101
+
102
+ GL.Material GL::FRONT, GL::AMBIENT, [0.05375, 0.05, 0.06625, 1.0]
103
+ GL.Material GL::FRONT, GL::DIFFUSE, [0.18275, 0.17, 0.22525, 1.0]
104
+ GL.Material GL::FRONT, GL::SPECULAR, [0.332741, 0.328634, 0.346435, 1.0]
105
+ GL.Material GL::FRONT, GL::SHININESS, 0.3 * 128.0
106
+
107
+ GL.PushMatrix
108
+ GL.Scale 1.0, 1.0, 0.1
109
+ GL.Translate 0.0, 0.0, -0.1
110
+
111
+ GLUT.SolidCube 1.0
112
+ GL.PopMatrix
113
+ end
114
+
115
+ def solid_cylinder(radius, height, slices, stacks)
116
+ GL.PushAttrib GL::POLYGON_BIT
117
+ GL.PolygonMode GL::FRONT_AND_BACK, GL::FILL
118
+ obj = GLU.NewQuadric
119
+ GLU.Cylinder obj, radius, radius, height, slices, stacks
120
+ GL.PushMatrix
121
+ GL.Translate 0.0, 0.0, height
122
+ GLU.Disk obj, 0.0, radius, slices, stacks
123
+ GL.PopMatrix
124
+ GLU.DeleteQuadric obj
125
+ GL.PopAttrib
126
+ end
127
+
128
+ def render_wall
129
+ GL.Material GL::FRONT, GL::AMBIENT, [0.0, 0.0, 0.0, 1.0]
130
+ GL.Material GL::FRONT, GL::DIFFUSE, [0.1, 0.35, 0.1, 1.0]
131
+ GL.Material GL::FRONT, GL::SPECULAR, [0.45, 0.55, 0.45, 1.0]
132
+ GL.Material GL::FRONT, GL::SHININESS, 0.25 * 128.0
133
+
134
+ GL.PushMatrix
135
+ GL.Translate 0.0, 0.0, 0.5
136
+
137
+ solid_cylinder 0.45, 1.0, 16, 4
138
+ GL.PopMatrix
139
+ end
140
+
141
+ game = Sokoban.new
142
+
143
+ display = lambda do
144
+ GL.Clear GL::COLOR_BUFFER_BIT | GL::DEPTH_BUFFER_BIT
145
+
146
+ screen = game.display
147
+ puts screen.class
148
+ screen = screen.split("\n")
149
+ puts screen.class
150
+
151
+ screen.each_with_index do |row, y|
152
+ row.chomp!
153
+ first = row =~ /^(\s+)/ ? $1.length : 0
154
+ (first...row.length).each do |x|
155
+ GL.PushMatrix
156
+ GL.Translate 1.0 + x, 17.5 - y, 0.0
157
+
158
+ if row[x, 1] == "." or row[x, 1] == "*" or row[x, 1] == "+"
159
+ render_storage
160
+ else
161
+ render_open_floor
162
+ end
163
+ if row[x, 1] == "@" or row[x, 1] == "+"
164
+ render_man
165
+ elsif row[x, 1] == "o"
166
+ render_crate
167
+ elsif row[x, 1] == "*"
168
+ render_stored_crate
169
+ elsif row[x, 1] == "#"
170
+ render_wall
171
+ end
172
+ GL.PopMatrix
173
+ end
174
+ end
175
+
176
+ GL.Flush
177
+ end
178
+
179
+ reshape = lambda do |w, h|
180
+ puts w
181
+ puts h
182
+
183
+ GL.Viewport 0, 0, w, h
184
+ GL.MatrixMode GL::PROJECTION
185
+ GL.LoadIdentity
186
+ GL.Frustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0)
187
+ GL.MatrixMode GL::MODELVIEW
188
+ GLU.LookAt 10.0, 10.0, 17.5, 10.0, 10.0, 0.0, 0.0, 1.0, 0.0
189
+ end
190
+
191
+ keyboard = lambda do |key, x, y|
192
+ case key
193
+ when ?Q, ?\C-c
194
+ exit 0
195
+ when ?S
196
+ game.save
197
+ when ?L
198
+ if test ?e, File.join(PATH, "sokoban_saved_game.yaml")
199
+ game = Sokoban.load
200
+ end
201
+ when ?R
202
+ game.restart_level
203
+ when ?N
204
+ game.load_level
205
+ when ?U
206
+ game.undo
207
+ when ?j, ?j
208
+ game.move_left
209
+ when ?k, ?K
210
+ game.move_right
211
+ when ?m, ?m
212
+ game.move_down
213
+ when ?i, ?I
214
+ game.move_up
215
+ end
216
+
217
+ if game.level_solved?
218
+ game.load_level
219
+
220
+ exit 0 if game.over?
221
+ end
222
+
223
+ GLUT.PostRedisplay
224
+ end
225
+
226
+ GLUT.Init
227
+ GLUT.InitDisplayMode GLUT::SINGLE | GLUT::RGB | GLUT::DEPTH
228
+ GLUT.CreateWindow "Sokoban"
229
+
230
+ init
231
+
232
+ GLUT.KeyboardFunc keyboard
233
+ GLUT.ReshapeFunc reshape
234
+ GLUT.DisplayFunc display
235
+
236
+ GLUT.MainLoop
data/bin/run ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../lib/sokoban'
3
+
4
+ #RubyWarrior::UI.out_stream = STDOUT
5
+ #RubyWarrior::UI.in_stream = STDIN
6
+ #RubyWarrior::UI.delay = 0.8 # TODO allow customization
7
+
8
+
9
+ game = Sokoban::Game.new # TODO pass options into game when initializing
10
+ game.start
11
+