meiro 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,57 @@
1
+ module Meiro
2
+ class RogueLikeTileManager < TileManager
3
+ class << self
4
+ def classify(tiles)
5
+ target = tiles[1, 1]
6
+ if target.walkable?
7
+ target
8
+ else
9
+ pattern = get_3x3_tile_pattern(tiles)
10
+ pattern_tile_map[pattern].new
11
+ end
12
+ end
13
+
14
+ def get_3x3_tile_pattern(tiles)
15
+ pattern = ""
16
+ tiles.each_tile do |x, y, tile|
17
+ s = (tile.instance_of?(flat)) ? '1' : '0'
18
+ pattern << s
19
+ end
20
+ pattern.to_i(2)
21
+ end
22
+
23
+ # 3x3のタイルパターンから、中心のタイルが何に分類されるかを
24
+ # 示すマップを返す。1は床を、0は床以外を意味する。よって、
25
+ #
26
+ # 0b000_000_000 は
27
+ #
28
+ # 000
29
+ # 000
30
+ # 000
31
+ #
32
+ # を、すなわち9マス全て床以外となっている状態を意味する。
33
+ def pattern_tile_map
34
+ @pattern_tile_map ||
35
+ @pattern_tile_map = {
36
+ 0b000_000_000 => wall,
37
+ 0b000_000_001 => l_wall,
38
+ 0b000_000_011 => t_wall,
39
+ 0b000_000_100 => r_wall,
40
+ 0b000_000_110 => t_wall,
41
+ 0b000_000_111 => t_wall,
42
+ 0b000_001_001 => l_wall,
43
+ 0b000_100_100 => r_wall,
44
+ 0b001_000_000 => l_wall,
45
+ 0b001_001_000 => l_wall,
46
+ 0b001_001_001 => l_wall,
47
+ 0b011_000_000 => b_wall,
48
+ 0b100_000_000 => r_wall,
49
+ 0b100_100_000 => r_wall,
50
+ 0b100_100_100 => r_wall,
51
+ 0b110_000_000 => b_wall,
52
+ 0b111_000_000 => b_wall,
53
+ }
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ module Meiro
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'meiro/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "meiro"
8
+ spec.version = Meiro::VERSION
9
+ spec.authors = ["Yuki Morohoshi"]
10
+ spec.email = ["hoshi.sanou@gmail.com"]
11
+ spec.summary = %q{Random Dungeon Generator}
12
+ spec.description = %q{Meiro generates maps used for so-called Rogue-like games.}
13
+ spec.homepage = "http://github.com/hoshi-sano/meiro"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "simplecov"
25
+ end
@@ -0,0 +1,460 @@
1
+ require 'spec_helper'
2
+
3
+ class Meiro::Block
4
+ # テスト用にアクセス可能にする
5
+ attr_accessor :parent, :shape
6
+
7
+ # テスト用にpublic実行可能にする
8
+ public :vertical_separate, :horizontal_separate
9
+ end
10
+
11
+ describe Meiro::Block do
12
+ let(:dungeon) { Meiro::Dungeon.new }
13
+ let(:floor) do
14
+ args = [dungeon, dungeon.width, dungeon.height,
15
+ dungeon.min_room_width, dungeon.min_room_height,
16
+ dungeon.max_room_width, dungeon.max_room_height,]
17
+ Meiro::Floor.new(*args)
18
+ end
19
+
20
+ let(:x) { 0 }
21
+ let(:y) { 0 }
22
+ let(:width) { 60 }
23
+ let(:height) { 40 }
24
+ let(:parent) { nil }
25
+ let(:block) { described_class.new(floor, x, y, width, height, parent) }
26
+
27
+ shared_examples 'vertical' do
28
+ its(:shape) { should eq(:vertical) }
29
+ end
30
+
31
+ shared_examples 'horizontal' do
32
+ its(:shape) { should eq(:horizontal) }
33
+ end
34
+
35
+ describe '.new' do
36
+ shared_examples 'basic_parameters' do
37
+ its(:x) { x }
38
+ its(:y) { y }
39
+ its(:width) { width }
40
+ its(:height) { height }
41
+ end
42
+
43
+ subject { described_class.new(floor, x, y, width, height, parent) }
44
+
45
+ context 'rootの場合' do
46
+ context '横長の場合' do
47
+ include_examples 'basic_parameters'
48
+ include_examples 'horizontal'
49
+ its(:parent) { should be_nil }
50
+ end
51
+
52
+ context '縦長の場合' do
53
+ let(:height) { 70 }
54
+ include_examples 'basic_parameters'
55
+ include_examples 'vertical'
56
+ its(:parent) { should be_nil }
57
+ end
58
+ end
59
+
60
+ context 'parentがいる場合' do
61
+ let(:parent) { described_class.new(floor, x, y, width, height, nil) }
62
+
63
+ context '横長の場合' do
64
+ include_examples 'basic_parameters'
65
+ include_examples 'horizontal'
66
+ its(:parent) { should_not be_nil }
67
+ end
68
+
69
+ context '縦長の場合' do
70
+ let(:height) { 70 }
71
+ include_examples 'basic_parameters'
72
+ include_examples 'vertical'
73
+ its(:parent) { should_not be_nil }
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#separate' do
79
+ subject { block.separate }
80
+
81
+ context '返り値' do
82
+ context '分割可能なBlockの場合' do
83
+ context '横長の場合' do
84
+ it { should be_true }
85
+ end
86
+
87
+ context '縦長の場合' do
88
+ let(:height) { 70 }
89
+ it { should be_true }
90
+ end
91
+ end
92
+
93
+ context '分割不可能なBlockの場合' do
94
+ let(:width) { 5 }
95
+ let(:height) { 5 }
96
+
97
+ it { should be_false }
98
+ end
99
+ end
100
+
101
+ context '@separated' do
102
+ before(:each) { block.separate }
103
+
104
+ context '分割可能なBlockの場合' do
105
+ it { block.separated?.should be_true }
106
+ end
107
+
108
+ context '分割不可能なBlockの場合' do
109
+ let(:width) { 5 }
110
+ let(:height) { 5 }
111
+
112
+ it { block.separated?.should be_false }
113
+ end
114
+ end
115
+ end
116
+
117
+ describe '#separatable?' do
118
+ subject { block.separatable? }
119
+
120
+ context '分割可能で' do
121
+ context '横長の場合' do
122
+ it { should be_true }
123
+ end
124
+
125
+ context '縦長の場合' do
126
+ let(:height) { 70 }
127
+
128
+ it { should be_true }
129
+ end
130
+ end
131
+
132
+ context '分割不可能で' do
133
+ context '横長の場合' do
134
+ let(:width) { 10 }
135
+ let(:height) { 5 }
136
+
137
+ it { should be_false }
138
+ end
139
+
140
+ context '縦長の場合' do
141
+ let(:width) { 5 }
142
+ let(:height) { 10 }
143
+
144
+ it { should be_false }
145
+ end
146
+ end
147
+ end
148
+
149
+ describe '#brother' do
150
+ context 'rootの場合' do
151
+ subject { block.brother }
152
+
153
+ it { should be_nil }
154
+ end
155
+
156
+ context 'parentがいるBlock' do
157
+ before(:each) { block.separate }
158
+
159
+ context 'upper_leftの場合' do
160
+ subject { block.upper_left.brother }
161
+
162
+ it { should eq(block.lower_right) }
163
+ end
164
+
165
+ context 'lower_rightの場合' do
166
+ subject { block.lower_right.brother }
167
+
168
+ it { should eq(block.upper_left) }
169
+ end
170
+ end
171
+ end
172
+
173
+ describe '#neighbors' do
174
+ context 'rootの場合' do
175
+ subject { block.neighbors }
176
+
177
+ it { should eq([]) }
178
+ end
179
+
180
+ context 'root1回分割済み' do
181
+ # +---+---+
182
+ # | 1 | 2 |
183
+ # +---+---+
184
+ before(:each) { floor.root_block.separate }
185
+
186
+ # 1
187
+ context 'upper_leftの場合' do
188
+ subject { floor.root_block.upper_left.neighbors }
189
+
190
+ it { should eq([floor.root_block.lower_right]) }
191
+ end
192
+
193
+ # 2
194
+ context 'lower_rightの場合' do
195
+ subject { floor.root_block.lower_right.neighbors }
196
+
197
+ it { should eq([floor.root_block.upper_left]) }
198
+ end
199
+ end
200
+
201
+ context 'root2回分割済み' do
202
+ # +---+---+
203
+ # | 1 | 3 |
204
+ # +---+---+
205
+ # | 2 | 4 |
206
+ # +---+---+
207
+ before(:each) do
208
+ floor.root_block.separate
209
+ floor.root_block.upper_left.separate
210
+ floor.root_block.lower_right.separate
211
+ end
212
+
213
+ # 1
214
+ context 'upper_left.upper_leftの場合' do
215
+ subject { floor.root_block.upper_left.upper_left.neighbors }
216
+
217
+ it { should eq([floor.root_block.lower_right.upper_left, # 3
218
+ floor.root_block.upper_left.lower_right]) } # 2
219
+ end
220
+
221
+ # 2
222
+ context 'upper_left.lower_rightの場合' do
223
+ subject { floor.root_block.upper_left.lower_right.neighbors }
224
+
225
+ it { should eq([floor.root_block.lower_right.lower_right, # 4
226
+ floor.root_block.upper_left.upper_left]) } # 1
227
+ end
228
+
229
+ # 3
230
+ context 'lower_right.upper_leftの場合' do
231
+ subject { floor.root_block.lower_right.upper_left.neighbors }
232
+
233
+ it { should eq([floor.root_block.upper_left.upper_left, # 1
234
+ floor.root_block.lower_right.lower_right]) } # 4
235
+ end
236
+
237
+ # 4
238
+ context 'lower_right.lower_rightの場合' do
239
+ subject { floor.root_block.lower_right.lower_right.neighbors }
240
+
241
+ it { should eq([floor.root_block.upper_left.lower_right, # 2
242
+ floor.root_block.lower_right.upper_left]) } # 3
243
+ end
244
+ end
245
+ end
246
+
247
+ describe '#generation' do
248
+ subject { block.generation }
249
+
250
+ context 'rootの場合' do
251
+ it { should eq(1) }
252
+ end
253
+
254
+ context 'rootを分割したBlockの場合' do
255
+ let(:parent) { described_class.new(floor, x, y, width, height, nil) }
256
+ let(:block) { described_class.new(floor, x, y, width, height, parent) }
257
+
258
+ it { should eq(2) }
259
+ end
260
+
261
+ context 'rootを分割したBlockを分割したBlockの場合' do
262
+ let(:grandparent) { described_class.new(floor, x, y, width, height, nil) }
263
+ let(:parent) { described_class.new(floor, x, y, width, height, grandparent) }
264
+ let(:block) { described_class.new(floor, x, y, width, height, parent) }
265
+
266
+ it { should eq(3) }
267
+ end
268
+ end
269
+
270
+ describe '#flatten' do
271
+ subject { block.flatten }
272
+
273
+ context '分割していない場合' do
274
+ it { should eq([block]) }
275
+ end
276
+
277
+ context '1回分割したBlockの場合' do
278
+ before(:each) { block.separate }
279
+
280
+ it { should eq([block.upper_left, block.lower_right]) }
281
+ end
282
+
283
+ context '2回分割したBlockの場合' do
284
+ before(:each) do
285
+ block.separate
286
+ block.upper_left.separate
287
+ block.lower_right.separate
288
+ end
289
+
290
+ it { should eq([block.upper_left.upper_left,
291
+ block.upper_left.lower_right,
292
+ block.lower_right.upper_left,
293
+ block.lower_right.lower_right,]) }
294
+ end
295
+ end
296
+
297
+ describe '#put_room' do
298
+ subject { block.put_room(randomizer_or_room) }
299
+
300
+ context '不正な引数を渡した場合' do
301
+ let(:randomizer_or_room) { 1 }
302
+
303
+ it { should be_false }
304
+ end
305
+
306
+ context '引数にRoomを渡す' do
307
+ let(:randomizer_or_room) { room }
308
+
309
+ context 'RoomがBlockに配置できない大きさだった場合' do
310
+ let(:room) { Meiro::Room.new(width, height) }
311
+
312
+ it { should be_false }
313
+ end
314
+
315
+ context 'RoomがBlockに配置可能な大きさだった場合' do
316
+ let(:room) { Meiro::Room.new(width - 2, height - 2) }
317
+
318
+ it { should be_true }
319
+ end
320
+ end
321
+
322
+ context '引数に乱数器を渡した場合' do
323
+ let(:randomizer_or_room) { Random.new(1) }
324
+
325
+ it { should be_true }
326
+ end
327
+
328
+ context '引数にnilを渡した場合' do
329
+ let(:randomizer_or_room) { nil }
330
+
331
+ it { should be_true }
332
+ end
333
+ end
334
+
335
+ shared_examples 'separated check' do
336
+ its(:upper_left) { should be_instance_of(described_class) }
337
+ its(:lower_right) { should be_instance_of(described_class) }
338
+ its(:partition) { should be_instance_of(Meiro::Partition) }
339
+ end
340
+
341
+ shared_examples 'separated height check' do
342
+ it '分割したBlockの高さの合計+1(Partition分)が分割前の高さと等しい' do
343
+ (subject.upper_left.height +
344
+ subject.lower_right.height + 1).should eq(height)
345
+ end
346
+ end
347
+
348
+ describe '#horizontal_separate' do
349
+ let(:separated) { block.horizontal_separate }
350
+ subject { separated }
351
+
352
+ context '高さが偶数の場合' do
353
+ let(:width) { 10 }
354
+ let(:height) { 20 }
355
+
356
+ include_examples 'separated check'
357
+ include_examples 'separated height check'
358
+
359
+ its('upper_left.x') { should eq(0) }
360
+ its('upper_left.y') { should eq(0) }
361
+ its('upper_left.width') { should eq(10) }
362
+ its('upper_left.height') { should eq(10) }
363
+ its('upper_left.generation') { should eq(2) }
364
+
365
+ its('partition.x') { should eq(0) }
366
+ its('partition.y') { should eq(10) }
367
+ its('partition.length') { should eq(10) }
368
+
369
+ its('lower_right.x') { should eq(0) }
370
+ its('lower_right.y') { should eq(11) }
371
+ its('lower_right.width') { should eq(10) }
372
+ its('lower_right.height') { should eq(9) }
373
+ its('lower_right.generation') { should eq(2) }
374
+ end
375
+
376
+ context '高さが奇数の場合' do
377
+ let(:width) { 10 }
378
+ let(:height) { 21 }
379
+
380
+ include_examples 'separated check'
381
+ include_examples 'separated height check'
382
+
383
+ its('upper_left.x') { should eq(0) }
384
+ its('upper_left.y') { should eq(0) }
385
+ its('upper_left.width') { should eq(10) }
386
+ its('upper_left.height') { should eq(10) }
387
+ its('upper_left.generation') { should eq(2) }
388
+
389
+ its('partition.x') { should eq(0) }
390
+ its('partition.y') { should eq(10) }
391
+ its('partition.length') { should eq(10) }
392
+
393
+ its('lower_right.x') { should eq(0) }
394
+ its('lower_right.y') { should eq(11) }
395
+ its('lower_right.width') { should eq(10) }
396
+ its('lower_right.height') { should eq(10) }
397
+ its('lower_right.generation') { should eq(2) }
398
+ end
399
+ end
400
+
401
+ shared_examples 'separated width check' do
402
+ it '分割したBlockの幅の合計+1(Partition分)が分割前の幅と等しい' do
403
+ (subject.upper_left.width +
404
+ subject.lower_right.width + 1).should eq(width)
405
+ end
406
+ end
407
+
408
+ describe '#vertical_separate' do
409
+ let(:separated) { block.vertical_separate }
410
+ subject { separated }
411
+
412
+ context '幅が偶数の場合' do
413
+ let(:width) { 20 }
414
+ let(:height) { 10 }
415
+
416
+ include_examples 'separated check'
417
+ include_examples 'separated width check'
418
+
419
+ its('upper_left.x') { should eq(0) }
420
+ its('upper_left.y') { should eq(0) }
421
+ its('upper_left.width') { should eq(10) }
422
+ its('upper_left.height') { should eq(10) }
423
+ its('upper_left.generation') { should eq(2) }
424
+
425
+ its('partition.x') { should eq(10) }
426
+ its('partition.y') { should eq(0) }
427
+ its('partition.length') { should eq(10) }
428
+
429
+ its('lower_right.x') { should eq(11) }
430
+ its('lower_right.y') { should eq(0) }
431
+ its('lower_right.width') { should eq(9) }
432
+ its('lower_right.height') { should eq(10) }
433
+ its('lower_right.generation') { should eq(2) }
434
+ end
435
+
436
+ context '幅が奇数の場合' do
437
+ let(:width) { 21 }
438
+ let(:height) { 10 }
439
+
440
+ include_examples 'separated check'
441
+ include_examples 'separated width check'
442
+
443
+ its('upper_left.x') { should eq(0) }
444
+ its('upper_left.y') { should eq(0) }
445
+ its('upper_left.width') { should eq(10) }
446
+ its('upper_left.height') { should eq(10) }
447
+ its('upper_left.generation') { should eq(2) }
448
+
449
+ its('partition.x') { should eq(10) }
450
+ its('partition.y') { should eq(0) }
451
+ its('partition.length') { should eq(10) }
452
+
453
+ its('lower_right.x') { should eq(11) }
454
+ its('lower_right.y') { should eq(0) }
455
+ its('lower_right.width') { should eq(10) }
456
+ its('lower_right.height') { should eq(10) }
457
+ its('lower_right.generation') { should eq(2) }
458
+ end
459
+ end
460
+ end