Skip to content

Commit

Permalink
Use an objects in the map builder
Browse files Browse the repository at this point in the history
  • Loading branch information
dwhenry committed Aug 5, 2017
1 parent 5bcc81b commit cfc2be2
Showing 1 changed file with 127 additions and 62 deletions.
189 changes: 127 additions & 62 deletions lib/game/map_builder.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,91 @@
class Game
class MapBuilder
def initialize(height, width)
@map = height.times.map do
width.times.map do
1
class Node
attr_accessor :top, :bottom, :left, :right, :visited, :steps

def initialize
@visited = false
@steps = nil
end

def start
@visited = true
@steps = 0
end

def visited?(direction)
cell(direction) && cell(direction).visited
end

def wall?(direction)
!visited?(direction)
end

def move(direction)
cell(direction).tap do |node|
node.visited = true
node.steps = steps + 1
end
end

def add_left(node)
return unless node
self.left = node
node.right = self
add_top(left.top && left.top.right)
end

def add_top(node)
return unless node
self.top = node
top.bottom = self
end

def dist(node)
((x - node.x) * (x - node.x)) + ((y - node.y) * (y - node.y))
end

def x
@x ||= left ? left.x + 1 : 0
end

def y
@y ||= top ? top.y + 1 : 0
end

def free(node)
([left, right, top, bottom].compact - [node]).none?(&:visited)
end

private

def cell(direction)
{
left: left,
right: right,
top: top,
bottom: bottom,
}.fetch(direction)
end
end

def initialize(height, width, start_location)
col_node = nil
@map = Array.new(height) do
row_node = nil
Array.new(width) do
new_node = Node.new
if row_node
new_node.add_left(row_node)
row_node = new_node
else
new_node.add_top(col_node)
row_node = col_node = new_node
end
end
end
@end_point = [height - 1, width - 1]
@endpoints = []
@start_location = start_location
@start_tile = @map[start_location[0]][start_location[1]]
add_paths
end

Expand All @@ -20,8 +97,8 @@ def place_objects(objects)
objects.map do |object|
location = next_endpoint
if location
object['x'] = location[0]
object['y'] = location[1]
object['x'] = location.x
object['y'] = location.y
end
object
end
Expand All @@ -30,87 +107,87 @@ def place_objects(objects)
private

def next_endpoint
location = @endpoints.sort_by(&:last)[-5..-1].sample
location = @endpoints.sort_by(&:steps)[-5..-1].sample
@endpoints -= [location]
location[0]
location
end

def add_paths
location = [@start_location[0], @start_location[1] + 2]
@map[@start_location[0]][@start_location[1]] = 0
@map[@start_location[0]][@start_location[1] + 1] = 0
@map[@start_location[0]][@start_location[1] + 2] = 0
@start_tile.start
location = @start_tile.move(:right)
location = location.move(:right)

branches = [[location, 0]]
branches = [@start_tile]
terminated = []
steps = 2

while true do
action = next_action(branches, location)
case action
when :move
# print 'm'
location = next_location(location, branches, steps)
direction = next_direction(location)

if location != :blocked
@map[location[0]][location[1]] = 0
steps += 1
if direction == :blocked
location = direction
else
location = location.move(direction)
end
when :branch
branches << [location, steps]
branches << location
# print "b#{branches.count}"
when :terminate
terminated << [location, steps]
location, steps = *(branches.sample)
branches.reject! { |b, _| b == location }
# print "t#{branches.count}"
terminated << location
location = branches.sample
branches -= [location]
print "t#{branches.count}"
else
location, steps = *(terminated.pop)
# print "X"
location = terminated.pop
print "X"
next if location
# no more moves so we are stuck
break
end
end

end

def next_action(branches, location)

options = []
options << :terminate if branches.count > 2
options << :terminate if branches.count > 5

unless location == :blocked
options << :move << :move << :move << :move << :move << :move

closest_branch = branches.sort_by { |b, _| dist_between(location, b) }.first[0]
options << :branch << :branch if !closest_branch || dist_between(closest_branch, location) > 4
options << :branch << :branch if !closest_branch || dist_between(closest_branch, location) > 6
options << :branch << :branch if !closest_branch || dist_between(closest_branch, location) > 9
closest_branch = branches.sort_by { |b| location.dist(b) }.first

if closest_branch
dist = location.dist(closest_branch)
options << :branch << :branch if dist > 4
options << :branch << :branch if dist > 6
options << :branch << :branch if dist > 9
end
end

options.sample
end

def map_walls(map)
map.map.with_index do |row, i|
row.map.with_index do |cell, j|
if cell == 0
map.map.with_index do |row|
row.map.with_index do |cell|
if cell.visited
Game::Tile::EMPTY_CELL
elsif at(i, j - 1) && at(i, j + 1)
if at(i + 1, j) || at(i - 1, j)
elsif cell.wall?(:left) && cell.wall?(:right)
if cell.wall?(:top) || cell.wall?(:bottom)
Game::Tile::WALL_CORNER
else
Game::Tile::WALL_0
end
elsif at(i, j + 1)
elsif cell.wall?(:right)
Game::Tile::WALL_CORNER_RIGHT
elsif at(i, j - 1)
elsif cell.wall?(:left)
Game::Tile::WALL_CORNER_LEFT
elsif at(i + 1, j) && at(i - 1, j)
elsif cell.wall?(:top) && cell.wall?(:bottom)
Game::Tile::WALL_90
elsif at(i + 1, j) || at(i - 1, j)
elsif cell.wall?(:top) || cell.wall?(:bottom)
Game::Tile::WALL_END
else
Game::Tile::WALL_SPOT
Expand All @@ -119,33 +196,21 @@ def map_walls(map)
end
end

def next_location(location, branches, steps)
x, y = *location

def next_direction(location)
# get a list of moveable locations
surroundings = []
surroundings << [x + 1, y] if at(x + 1, y) && at(x + 2, y) && (at(x + 1, y + 1) && at(x + 1, y - 1))
surroundings << [x - 1, y] if at(x - 1, y) && at(x - 2, y) && (at(x - 1, y + 1) && at(x - 1, y - 1))
surroundings << [x, y + 1] if at(x, y + 1) && at(x, y + 2) && (at(x + 1, y + 1) && at(x - 1, y + 1))
surroundings << [x, y - 1] if at(x, y - 1) && at(x, y - 2) && (at(x + 1, y - 1) && at(x - 1, y - 1))

# print "s#{surroundings.count}"
%i[left right top bottom].each do |direction|
node = location.send(direction)
surroundings << direction if node && node.free(location)
end
print "s#{surroundings.count}"
if surroundings.any?
surroundings.sample
else
@endpoints << [location, steps]
@endpoints << location

:blocked
end
end

def dist_between(a, b)
((a[0] - b[0]) * (a[0] - b[0])) + ((a[1] - b[1]) * (a[1] - b[1]))
end

def at(x, y)
return nil if x < 0 || y < 0
@map[x] && @map[x][y] == 1
end
end
end

0 comments on commit cfc2be2

Please sign in to comment.