sokobanrb 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "yaml"
4
+
5
+ module Sokoban1
6
+ class Sokoban
7
+ WALL = "#"
8
+ OPEN_FLOOR = " "
9
+
10
+ MAN = "@"
11
+ CRATE = "o"
12
+
13
+ STORAGE = "."
14
+ MAN_ON_STORAGE = "+"
15
+ CRATE_ON_STORAGE = "*"
16
+
17
+ MAX_UNDO = 10
18
+
19
+ PATH = File.expand_path(File.dirname(__FILE__))
20
+
21
+ attr_reader :level, :moves
22
+
23
+ def self.load( file = File.join(PATH, "sokoban_saved_game.yaml") )
24
+ game = nil
25
+
26
+ File.open file do |f|
27
+ game = YAML.load(f)
28
+ end
29
+
30
+ game ||= Sokoban.new
31
+ game
32
+ end
33
+
34
+ def initialize( file = File.join(PATH, "sokoban_levels.txt") )
35
+ @level_file = file
36
+
37
+ @board = [ ]
38
+ @level = 0
39
+ @over = false
40
+
41
+ @undos = [ ]
42
+ @moves = 0
43
+
44
+ load_level
45
+ end
46
+
47
+ def can_move_down?( ) can_move? :down end
48
+ def can_move_left?( ) can_move? :left end
49
+ def can_move_right?( ) can_move? :right end
50
+ def can_move_up?( ) can_move? :up end
51
+
52
+ def display
53
+ @board.inject("") { |dis, row| dis + row.join + "\n" }
54
+ end
55
+
56
+ def level_solved?
57
+ @board.each_with_index do |row, y|
58
+ row.each_with_index do |cell, x|
59
+ return false if cell == CRATE
60
+ end
61
+ end
62
+ true
63
+ end
64
+
65
+ def load_level( level = @level += 1, file = @level_file )
66
+ loaded = false
67
+
68
+ File.open file do |f|
69
+ count = 0
70
+ while lvl = f.gets("")
71
+ count += 1
72
+ if count == level
73
+ @board = [ ]
74
+ lvl.chomp!
75
+ lvl.each_line { |e| @board << e.chomp.split("") }
76
+ loaded = true
77
+ break
78
+ end
79
+ end
80
+ end
81
+
82
+ if loaded
83
+ @undos = [ ]
84
+ @moves = 0
85
+ else
86
+ @over = true
87
+ end
88
+
89
+ loaded
90
+ end
91
+
92
+ def move_down( ) move :down end
93
+ def move_left( ) move :left end
94
+ def move_right( ) move :right end
95
+ def move_up( ) move :up end
96
+
97
+ def over?
98
+ @over
99
+ end
100
+
101
+ def restart_level
102
+ load_level @level
103
+ end
104
+
105
+ def save( file = File.join(PATH, "sokoban_saved_game.yaml") )
106
+ File.open(file, "w") do |f|
107
+ f << YAML.dump(self)
108
+ end
109
+ end
110
+
111
+ def undo
112
+ if @undos.size > 0
113
+ @board = @undos.pop
114
+ @moves -= 1
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ def can_move?( dir )
121
+ x, y = where_am_i
122
+ case dir
123
+ when :down
124
+ first = @board[y + 1][x]
125
+ second = y < @board.size - 2 ? @board[y + 2][x] : nil
126
+ when :left
127
+ first = @board[y][x - 1]
128
+ second = x >= 2 ? @board[y][x - 2] : nil
129
+ when :right
130
+ first = @board[y][x + 1]
131
+ second = x < @board[y].size - 2 ? @board[y][x + 2] : nil
132
+ when :up
133
+ first = @board[y - 1][x]
134
+ second = y >= 2 ? @board[y - 2][x] : nil
135
+ end
136
+
137
+ if first == OPEN_FLOOR or first == STORAGE
138
+ true
139
+ elsif not second.nil? and
140
+ (first == CRATE or first == CRATE_ON_STORAGE) and
141
+ (second == OPEN_FLOOR or second == STORAGE)
142
+ true
143
+ else
144
+ false
145
+ end
146
+ end
147
+
148
+ def move( dir )
149
+ return false unless can_move? dir
150
+
151
+ @undos << Marshal.load(Marshal.dump(@board))
152
+ @undos.shift if @undos.size > MAX_UNDO
153
+ @moves += 1
154
+
155
+ x, y = where_am_i
156
+ case dir
157
+ when :down
158
+ if @board[y + 1][x] == CRATE or @board[y + 1][x] == CRATE_ON_STORAGE
159
+ move_crate x, y + 1, x, y + 2
160
+ end
161
+ move_man x, y, x, y + 1
162
+ when :left
163
+ if @board[y][x - 1] == CRATE or @board[y][x - 1] == CRATE_ON_STORAGE
164
+ move_crate x - 1, y, x - 2, y
165
+ end
166
+ move_man x, y, x - 1, y
167
+ when :right
168
+ if @board[y][x + 1] == CRATE or @board[y][x + 1] == CRATE_ON_STORAGE
169
+ move_crate x + 1, y, x + 2, y
170
+ end
171
+ move_man x, y, x + 1, y
172
+ when :up
173
+ if @board[y - 1][x] == CRATE or @board[y - 1][x] == CRATE_ON_STORAGE
174
+ move_crate x, y - 1, x, y - 2
175
+ end
176
+ move_man x, y, x, y - 1
177
+ end
178
+ true
179
+ end
180
+
181
+ def move_crate( from_x, from_y, to_x, to_y )
182
+ if @board[to_y][to_x] == STORAGE
183
+ @board[to_y][to_x] = CRATE_ON_STORAGE
184
+ else
185
+ @board[to_y][to_x] = CRATE
186
+ end
187
+ if @board[from_y][from_x] == CRATE_ON_STORAGE
188
+ @board[from_y][from_x] = STORAGE
189
+ else
190
+ @board[from_y][from_x] = OPEN_FLOOR
191
+ end
192
+ end
193
+
194
+ def move_man( from_x, from_y, to_x, to_y )
195
+ if @board[to_y][to_x] == STORAGE
196
+ @board[to_y][to_x] = MAN_ON_STORAGE
197
+ else
198
+ @board[to_y][to_x] = MAN
199
+ end
200
+ if @board[from_y][from_x] == MAN_ON_STORAGE
201
+ @board[from_y][from_x] = STORAGE
202
+ else
203
+ @board[from_y][from_x] = OPEN_FLOOR
204
+ end
205
+ end
206
+
207
+ def where_am_i
208
+ @board.each_with_index do |row, y|
209
+ row.each_with_index do |cell, x|
210
+ return x, y if cell == MAN or cell == MAN_ON_STORAGE
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,401 @@
1
+
2
+
3
+
4
+
5
+ module Sokoban1
6
+ class Render
7
+ class << self
8
+ attr_accessor :game
9
+
10
+ def render_man
11
+ unless @render_man
12
+ @render_man = glGenLists 1
13
+
14
+ glNewList(@render_man , GL_COMPILE)
15
+
16
+ glMaterialfv GL_FRONT, GL_AMBIENT,convert( [0.0, 0.0, 0.0, 1.0] )
17
+ glMaterialfv GL_FRONT, GL_DIFFUSE,convert( [0.5, 0.0, 0.0, 1.0] )
18
+ glMaterialfv GL_FRONT, GL_SPECULAR,convert( [0.7, 0.6, 0.6, 1.0] )
19
+ #glMaterialfv GL_FRONT, GL_SHININESS, 0.25 * 128.0 unless SHOW_FFI
20
+
21
+ glutSolidSphere 0.5, 16, 16
22
+ glEndList
23
+ end
24
+ glCallList @render_man
25
+ end
26
+
27
+ def render_crate
28
+ unless @render_crate
29
+ @render_crate = glGenLists 1
30
+
31
+ glNewList(@render_crate , GL_COMPILE)
32
+ glMaterialfv GL_FRONT, GL_AMBIENT,convert( [0.19125, 0.0735, 0.0225, 1.0] )
33
+ glMaterialfv GL_FRONT, GL_DIFFUSE,convert( [0.7038, 0.27048, 0.0828, 1.0] )
34
+ glMaterialfv GL_FRONT, GL_SPECULAR,convert( [0.256777, 0.137622, 0.086014, 1.0] )
35
+ #glMaterialfv GL_FRONT, GL_SHININESS, 0.1 * 128.0 unless SHOW_FFI
36
+
37
+ glPushMatrix
38
+ glScalef 0.9, 0.9, 0.9
39
+ glTranslatef 0.0, 0.0, 0.45
40
+
41
+ glutSolidCube 1.0
42
+ glPopMatrix
43
+ glEndList
44
+ end
45
+ glCallList @render_crate
46
+ end
47
+
48
+ def render_stored_crate
49
+ unless @render_stored_crate
50
+ @render_stored_crate = glGenLists 1
51
+
52
+ glNewList(@render_stored_crate , GL_COMPILE)
53
+
54
+ glMaterialfv GL_FRONT, GL_AMBIENT,convert( [0.25, 0.20725, 0.20725, 1.0] )
55
+ glMaterialfv GL_FRONT, GL_DIFFUSE,convert( [1.0, 0.829, 0.829, 1.0] )
56
+ glMaterialfv GL_FRONT, GL_SPECULAR,convert( [0.296648, 0.296648, 0.296648, 1.0] )
57
+ #glMaterialfv GL_FRONT, GL_SHININESS, 0.088 * 128.0 unless SHOW_FFI
58
+
59
+ glPushMatrix
60
+ glScalef 0.9, 0.9, 0.9
61
+ glTranslatef 0.0, 0.0, 0.45
62
+
63
+ glutSolidCube 1.0
64
+ glPopMatrix
65
+ glEndList
66
+ end
67
+ glCallList @render_stored_crate
68
+ end
69
+
70
+ def render_open_floor
71
+
72
+ unless @render_open_floor
73
+ @render_open_floor = glGenLists 1
74
+
75
+ glNewList(@render_open_floor, GL_COMPILE)
76
+
77
+ glMaterialfv GL_FRONT, GL_AMBIENT,convert( [0.05, 0.05, 0.05, 1.0] )
78
+ glMaterialfv GL_FRONT, GL_DIFFUSE,convert( [0.5, 0.5, 0.5, 1.0] )
79
+ glMaterialfv GL_FRONT, GL_SPECULAR,convert( [0.7, 0.7, 0.7, 1.0] )
80
+ #glMaterialfv GL_FRONT, GL_SHININESS, 0.078125 * 128.0
81
+
82
+
83
+
84
+ glPushMatrix
85
+ glScalef 0.9, 0.9, 0.1
86
+ glTranslatef 0.0, 0.0, -0.05
87
+
88
+ glutSolidCube 1.0
89
+ glPopMatrix
90
+
91
+ glMaterialfv GL_FRONT, GL_AMBIENT, convert( [0.05375, 0.05, 0.06625, 1.0] )
92
+ glMaterialfv GL_FRONT, GL_DIFFUSE, convert( [0.18275, 0.17, 0.22525, 1.0] )
93
+ glMaterialfv GL_FRONT, GL_SPECULAR, convert( [0.332741, 0.328634, 0.346435, 1.0] )
94
+ #glMaterialfv GL_FRONT, GL_SHININESS, 0.3 * 128.0 unless SHOW_FFI
95
+
96
+ glPushMatrix
97
+ glScalef 1.0, 1.0, 0.1
98
+ glTranslatef 0.0, 0.0, -0.1
99
+
100
+ glutSolidCube 1.0
101
+ glPopMatrix
102
+ glEndList
103
+ end
104
+ glCallList @render_open_floor
105
+ end
106
+
107
+ def render_storage
108
+
109
+ #glGenLists(1)
110
+ # Make the gears
111
+ unless @render_storage
112
+ puts 'REGISTER IN DISPLAY LIST'
113
+ @render_storage = glGenLists 1
114
+
115
+ glNewList(@render_storage, GL_COMPILE)
116
+ #glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,@mRED)
117
+ #gear(1.0, 4.0, 1.0, 20, 0.7)
118
+
119
+
120
+ glMaterialfv GL_FRONT, GL_AMBIENT, convert( [0.05, 0.05, 0.0, 1.0] )
121
+ glMaterialfv GL_FRONT, GL_DIFFUSE, convert( [0.5, 0.5, 0.4, 1.0] )
122
+ glMaterialfv GL_FRONT, GL_SPECULAR, convert( [0.7, 0.7, 0.04, 1.0] )
123
+ #glMaterialfv GL_FRONT, GL_SHININESS, 0.078125 * 128.0 unless SHOW_FFI
124
+
125
+
126
+ glPushMatrix
127
+ glScalef 0.9, 0.9, 0.1
128
+ glTranslatef 0.0, 0.0, -0.05
129
+
130
+ glutSolidCube 1.0
131
+ glPopMatrix
132
+
133
+ glMaterialfv GL_FRONT, GL_AMBIENT, convert([0.05375, 0.05, 0.06625, 1.0])
134
+ glMaterialfv GL_FRONT, GL_DIFFUSE, convert([0.18275, 0.17, 0.22525, 1.0])
135
+ glMaterialfv GL_FRONT, GL_SPECULAR, convert([0.332741, 0.328634, 0.346435, 1.0])
136
+ #glMaterialfv GL_FRONT, GL_SHININESS, 0.3 * 128.0 unless SHOW_FFI
137
+
138
+ glPushMatrix
139
+ glScalef 1.0, 1.0, 0.1
140
+ glTranslatef 0.0, 0.0, -0.1
141
+
142
+ glutSolidCube 1.0
143
+ glPopMatrix
144
+
145
+ glEndList()
146
+ end
147
+ #glPushMatrix()
148
+ #glTranslatef(-3.0, -2.0, 0.0)
149
+ #glRotatef(@angle, 0.0, 0.0, 1.0)
150
+ glCallList(@render_storage)
151
+ #glPopMatrix()
152
+
153
+ end
154
+
155
+ def solid_cylinder(radius, height, slices, stacks)
156
+
157
+ glPushAttrib GL_POLYGON_BIT
158
+ glPolygonMode GL_FRONT_AND_BACK, GL_FILL
159
+ obj = gluNewQuadric
160
+ gluCylinder obj, radius, radius, height, slices, stacks
161
+ glPushMatrix
162
+ glTranslatef 0.0, 0.0, height
163
+ gluDisk obj, 0.0, radius, slices, stacks
164
+ glPopMatrix
165
+ gluDeleteQuadric obj
166
+ glPopAttrib
167
+
168
+ end
169
+
170
+ def convert args
171
+ #puts args.class
172
+ if SHOW_FFI
173
+ MemoryPointer.new(:float, 4).put_array_of_float(0, args)
174
+ else
175
+ args
176
+ end
177
+
178
+
179
+
180
+ end
181
+ def render_wall
182
+
183
+ unless @render_wall
184
+ @render_wall = glGenLists 1
185
+
186
+ glNewList(@render_wall , GL_COMPILE)
187
+
188
+ glMaterialfv GL_FRONT, GL_AMBIENT, convert( [0.0, 0.0, 0.0, 1.0])
189
+ glMaterialfv GL_FRONT, GL_DIFFUSE, convert( [0.1, 0.35, 0.1, 1.0])
190
+ glMaterialfv GL_FRONT, GL_SPECULAR, convert( [0.45, 0.55, 0.45, 1.0])
191
+ #glMaterialfv GL_FRONT, GL_SHININESS, 0.25 * 128.0 unless SHOW_FFI
192
+
193
+ glPushMatrix
194
+ glTranslatef 0.0, 0.0, 0.5
195
+
196
+ solid_cylinder 0.45, 1.0, 16, 4
197
+ glPopMatrix
198
+ glEndList
199
+ end
200
+ glCallList @render_wall
201
+ end
202
+
203
+ def keyboard_not_ffi key , x , y
204
+ #= lambda do |key, x, y|
205
+ puts key
206
+ puts x
207
+ puts y
208
+ case key
209
+ when ?c
210
+ exit 0
211
+ when ?s
212
+ @game.save
213
+ #when ?l
214
+ #if test ?e, File.join(PATH, "sokoban_saved_@game.yaml")
215
+ #@game = Sokoban.load
216
+ #end
217
+ when ?r
218
+ @game.restart_level
219
+ when ?n
220
+ @game.load_level
221
+ when ?u
222
+ @game.undo
223
+ when ?j
224
+ @game.move_left
225
+ when ?l
226
+ @game.move_right
227
+ when ?k
228
+ @game.move_down
229
+ when ?i
230
+ #?i, ?I
231
+ @game.move_up
232
+ #puts 'move up'
233
+ when ?q
234
+ exit
235
+ end
236
+
237
+ if @game.level_solved?
238
+ @game.load_level
239
+
240
+ exit 0 if @game.over?
241
+ end
242
+
243
+ glutPostRedisplay
244
+ end
245
+
246
+
247
+ def keyboard_ffi key , x , y
248
+ #= lambda do |key, x, y|
249
+ puts key
250
+ puts x
251
+ puts y
252
+ case key
253
+ when ?c
254
+ exit 0
255
+ when ?s
256
+ @game.save
257
+ #when ?l
258
+ #if test ?e, File.join(PATH, "sokoban_saved_@game.yaml")
259
+ #@game = Sokoban.load
260
+ #end
261
+ when ?r
262
+ @game.restart_level
263
+ when ?n
264
+ @game.load_level
265
+ when ?u
266
+ @game.undo
267
+ when 104
268
+ @game.move_left
269
+ when 107
270
+ @game.move_right
271
+ when 106
272
+ @game.move_down
273
+ when 117
274
+ #?i, ?I
275
+ @game.move_up
276
+ #puts 'move up'
277
+ when 27
278
+ exit
279
+ end
280
+
281
+ if @game.level_solved?
282
+ @game.load_level
283
+
284
+ exit 0 if @game.over?
285
+ end
286
+
287
+ glutPostRedisplay
288
+ end
289
+
290
+
291
+
292
+
293
+ def display2
294
+ #= lambda do
295
+ puts 'render::display2() glClear (..)'
296
+ glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
297
+
298
+ #GLUT.InitDisplayMode GLUT::SINGLE | GLUT::RGB | GLUT::DEPTH
299
+
300
+ screen = @game.display
301
+ #puts screen.class
302
+ screen = screen.split("\n")
303
+ #puts screen.class
304
+ puts screen
305
+ screen.each_with_index do |row, y|
306
+ row.chomp!
307
+ first = row =~ /^(\s+)/ ? $1.length : 0
308
+ (first...row.length).each do |x|
309
+ glPushMatrix
310
+ glTranslatef 1.0 + x, 17.5 - y, 0.0
311
+
312
+ if row[x, 1] == "." or row[x, 1] == "*" or row[x, 1] == "+"
313
+ render_storage
314
+ else
315
+ render_open_floor
316
+ end
317
+ if row[x, 1] == "@" or row[x, 1] == "+"
318
+ render_man
319
+ elsif row[x, 1] == "o"
320
+ render_crate
321
+ elsif row[x, 1] == "*"
322
+ render_stored_crate
323
+ elsif row[x, 1] == "#"
324
+ render_wall
325
+ end
326
+ glPopMatrix
327
+ end
328
+ end
329
+
330
+ glFlush
331
+ glutSwapBuffers
332
+ end
333
+ def register_glut_with_soko
334
+
335
+ glutDisplayFunc (method(:display2).to_proc)
336
+ #glutIdleFunc(method(:idle).to_proc)
337
+
338
+ glutReshapeFunc (method(:reshape_soko).to_proc)
339
+
340
+ if SHOW_FFI
341
+
342
+ glutKeyboardFunc(method(:keyboard_ffi).to_proc)
343
+ else
344
+
345
+ glutKeyboardFunc(method(:keyboard_not_ffi).to_proc)
346
+ end
347
+
348
+ end
349
+ def init_soko
350
+
351
+ puts 'render think: SHOW_FFI is:'
352
+ puts SHOW_FFI
353
+
354
+ @game = Sokoban.new
355
+ end
356
+ def enable_light_soko
357
+ unless SHOW_FFI
358
+ puts 'Render::senable_light_soko() how ffi'
359
+ glLight GL_LIGHT0, GL_AMBIENT, [0.0, 0.0, 0.0, 1.0]
360
+ glLight GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1.0]
361
+ glLight GL_LIGHT0, GL_POSITION, [0.0, 3.0, 3.0, 0.0]
362
+ glLightModel GL_LIGHT_MODEL_AMBIENT, [0.2, 0.2, 0.2, 1.0]
363
+ glLightModel GL_LIGHT_MODEL_LOCAL_VIEWER, [0.0]
364
+ end
365
+
366
+ #GL.FrontFace GL::CW
367
+ #GL.Enable GL::LIGHTING
368
+ #GL.Enable GL::LIGHT0
369
+ #GL.Enable GL::AUTO_NORMAL
370
+ #GL.Enable GL::NORMALIZE
371
+ #GL.Enable GL::DEPTH_TEST
372
+ #GL.DepthFunc GL::LESS
373
+
374
+ glFrontFace GL_CW
375
+ glEnable GL_LIGHTING
376
+ glEnable GL_LIGHT0
377
+ glEnable GL_AUTO_NORMAL
378
+ glEnable GL_NORMALIZE
379
+ glEnable GL_DEPTH_TEST
380
+ glDepthFunc GL_LESS
381
+ end
382
+ # New window size or exposure
383
+ def reshape_soko(width, height)
384
+
385
+ h = height.to_f / width.to_f
386
+ glViewport(0, 0, width, height)
387
+ glMatrixMode(GL_PROJECTION)
388
+ glLoadIdentity()
389
+ glFrustum(-1.0, 1.0, -h, h, 1.5, 20.0)
390
+ glMatrixMode(GL_MODELVIEW)
391
+ glLoadIdentity()
392
+
393
+ gluLookAt 10.0, 10.0, 17.5, 10.0, 10.0, 0.0, 0.0, 1.0, 0.0
394
+ #glTranslatef(0.0, 0.0, -40.0)
395
+ #
396
+ glutPostRedisplay
397
+ end
398
+
399
+ end
400
+ end
401
+ end