meiro 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.
@@ -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