sokoban.rb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+