Skip to content

Commit

Permalink
check reuse of edges fixes #4287
Browse files Browse the repository at this point in the history
  • Loading branch information
tobymao committed Mar 16, 2021
1 parent e9251b4 commit 21fa9ef
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 7,734 deletions.
24 changes: 1 addition & 23 deletions lib/engine/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def self.connect!(hex)
hex.tile.paths.each do |path|
path.walk do |_, visited|
chain = visited.keys
next unless valid_connection?(chain)
next unless chain.sum { |p| p.nodes.size } > 1

path = chain[0]

Expand All @@ -29,28 +29,6 @@ def self.connect!(hex)
end
end

def self.valid_connection?(chain)
ends = Hash.new(0)
nodes = 0

chain.each do |path|
a = path.a
b = path.b

# invalid if edge or node appears more than once, or junction appears more than twice (loops)
return false if !a.junction? && ends[a.id].positive?
return false if !b.junction? && ends[b.id].positive?
return false if ends[a.id] > 1
return false if ends[b.id] > 1

ends[a.id] += 1
ends[b.id] += 1
nodes += path.nodes.size if nodes < 2
end

nodes > 1
end

def initialize(paths = [])
@paths = paths
@nodes = nil
Expand Down
15 changes: 12 additions & 3 deletions lib/engine/part/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,23 @@ def select(paths, corporation: nil)
# skip_track: If passed, don't walk on track of that type (ie: :broad track for 1873)
#
# This method recursively bubbles up yielded values from nested Node::Walk and Path::Walk calls
def walk(visited: {}, on: nil, corporation: nil, visited_paths: {}, skip_track: nil, tile_type: :normal)
def walk(
visited: {},
on: nil,
corporation: nil,
visited_paths: {},
counter: Hash.new(0),
skip_track: nil,
tile_type: :normal
)
return if visited[self]

visited[self] = true

paths.each do |node_path|
next if node_path.track == skip_track

node_path.walk(visited: visited_paths, on: on, tile_type: tile_type) do |path, vp|
node_path.walk(visited: visited_paths, counter: counter, on: on, tile_type: tile_type) do |path, vp, ct|
yield path
next if path.terminal?

Expand All @@ -63,11 +71,12 @@ def walk(visited: {}, on: nil, corporation: nil, visited_paths: {}, skip_track:

next_node.walk(
visited: visited,
counter: ct,
on: on,
corporation: corporation,
visited_paths: vp,
skip_track: skip_track,
tile_type: tile_type
tile_type: tile_type,
) { |p| yield p }
end
end
Expand Down
25 changes: 18 additions & 7 deletions lib/engine/part/path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,42 +105,53 @@ def select(paths)
# skip: An exit to ignore. Useful to prevent ping-ponging between adjacent hexes.
# jskip: An junction to ignore. May be useful on complex tiles
# visited: a hashset of visited Paths. Used to avoid repeating track segments.
# counter: a hash tracking edges and junctions to avoid reuse
# on: A set of Paths mapping to 1 or 0. When `on` is set. Usage is currently limited to `select` in path & node
def walk(skip: nil, jskip: nil, visited: {}, on: nil, tile_type: :normal)
# tile_type: if :lawson don't undo visited paths
def walk(skip: nil, jskip: nil, visited: {}, counter: Hash.new(0), on: nil, tile_type: :normal)
return if visited[self]
return if @junction && counter[@junction] > 1
return if edges.sum { |edge| counter[edge.id] }.positive?

visited[self] = true
counter[@junction] += 1 if @junction

yield self, visited
yield self, visited, counter

if @junction && @junction != jskip
@junction.paths.each do |jp|
next if on && !on[jp]

jp.walk(jskip: @junction, visited: visited, on: on, tile_type: tile_type) do |p, v|
yield p, v
jp.walk(jskip: @junction, visited: visited, counter: counter, on: on, tile_type: tile_type) do |p, v, c|
yield p, v, c
end
end
end

exits.each do |edge|
edges.each do |edge|
edge_id = edge.id
edge = edge.num
next if edge == skip
next unless (neighbor = hex.neighbors[edge])

counter[edge_id] += 1
np_edge = hex.invert(edge)

neighbor.paths[np_edge].each do |np|
next if on && !on[np]
next unless lane_match?(@exit_lanes[edge], np.exit_lanes[np_edge])
next unless tracks_match?(np, dual_ok: true)

np.walk(skip: np_edge, visited: visited, on: on, tile_type: tile_type) do |p, v|
yield p, v
np.walk(skip: np_edge, visited: visited, counter: counter, on: on, tile_type: tile_type) do |p, v, c|
yield p, v, c
end
end

counter[edge_id] -= 1
end

visited.delete(self) unless tile_type == :lawson
counter[@junction] -= 1 if @junction
end

# return true if facing exits on adjacent tiles match up taking lanes into account
Expand Down
Loading

0 comments on commit 21fa9ef

Please sign in to comment.