Permalink
Browse files

implemented zoc

  • Loading branch information...
1 parent 604f407 commit 18a952c850da24bd56f881ea593a131bb94aa16d @micktaiwan committed Nov 27, 2011
Showing with 153 additions and 126 deletions.
  1. +7 −15 bots/chuckbot.rb
  2. +4 −0 lib/game.rb
  3. +28 −18 lib/pathfinding.rb
  4. +11 −16 lib/unit.rb
  5. +103 −77 specs/pathfinding_tests.rb
View
@@ -25,7 +25,8 @@ def take_turn
# Move units
# TODO: make 2 loops on units that didn't move before doing something else
- units.sort_by{|u| [u.attack_range[0], -u.defense_strength, -u.hp, -u.speed(1)]}.each do |unit|
+ units.sort_by{|u| [u.speed(1)]}.each do |unit|
+ # [u.attack_range[0], -u.defense_strength, -u.hp, -u.speed(1)]
#next if !unit # useless, but in case we implement the remove myself if dead after attack feature
# After a victorious attack, the enemy is still in the array and therefore
@@ -80,20 +81,12 @@ def take_turn
# TODO: the capturer to go to the base shall be the nearest,
# it is not the case as we loop through the capturers first (and then select the nearest base)
# and not the bases first
- dest = unit.nearest(@game.neutral_bases.find_all { |b| !going_to_bases.include?(b)}, enemies)
+ dest = unit.nearest((@game.neutral_bases + @game.enemy_bases).find_all { |b| !going_to_bases.include?(b)}, enemies)
if dest
- moved = unit.move_to(dest,{:exclusions=>enemies, :also_attack=>[]})
+ moved = unit.move_to(dest,{:exclusions=>enemies, :also_attack=>@game.enemy_on_bases})
if moved
going_to_bases << dest
- puts " gone to neutral base #{dest}"
- end
- end
- if !dest
- dest = unit.nearest(@game.enemy_bases.find_all { |b| !going_to_bases.include?(b)}, enemies)
- moved = unit.move_to(dest,{:exclusions=>enemies, :also_attack=>weakers}) if dest
- if moved
- going_to_bases << dest
- puts " gone to enemy base #{dest}"
+ puts " gone to base #{dest}"
end
end
if !dest
@@ -105,7 +98,6 @@ def take_turn
# unit.find_target_and_safe_place
end
-
# TODO: attack enemies capturing our base
# TODO: if we are trying to attack nearest enemy, first use my_targets, it is quicker
if !moved
@@ -124,14 +116,14 @@ def take_turn
else
# TODO: must verify that enemy is in range, otherwise the unit could go very far....
dest = unit.nearest(attacked, all_others-attacked)
- dest = nil if unit.dist_between(dest) > unit.speed(1)-1
+ dest = nil if dest and unit.dist_between(dest) > unit.speed(1)-1
puts(" found attacked: #{dest}") if dest
end
if dest
# FIXME: a :bers can not move to woods so it can not attack the unit there !!!!
attacked += [dest] if !attacked.include?(dest)
puts(" #{unit} trying to move to #{dest}")
- moved = unit.move_to(dest,{:exclusions=>all_others-enemies, :also_attack=>enemies})
+ moved = unit.move_to(dest,{:exclusions=>all_others, :also_attack=>enemies})
# FIXME: unit.best_place_to_attack(dest)
puts(" moved ? => #{moved}")
end
View
@@ -260,6 +260,10 @@ def my_free_bases
my_bases.find_all{|b| !b.finished? and !b.unit}
end
+ def enemy_on_bases
+ (enemy_bases+neutral_bases).find_all { |b| b.unit and enemy_units.include?(b.unit)}
+ end
+
end
end
View
@@ -5,7 +5,7 @@ module Weewar
class Unit
# An Array of the Hex es which the given Unit can move to in the current turn.
# possible_moves = my_unit.destinations
- def destinations
+ def server_destinations
xml = XmlSimple.xml_in(@game.send("<movementOptions x='#{x}' y='#{y}' type='#{TYPE_FOR_SYMBOL[@type]}'/>"))
coords = xml['coordinate']
if !coords
@@ -22,16 +22,18 @@ def my_destinations_and_backchains(exclusions = [], from=nil)
openset = [from] # The set of tentative nodes to be evaluated, initially containing the start node
came_from = Hash.new # The map of navigated nodes.
cost = Hash.new
+ zoc_hash = Unit.init_zoc_hash(@game)
possibles = Array.new
cost[from] = 0 # Cost from start along best known path.
+
mob = mobility(1)
while not openset.empty?
x = openset.sort_by{ |x| cost[x]}.first
openset.delete(x)
closedset.push(x)
for y in x.neighbours
next if closedset.include?(y)
- ec = entrance_cost(y)
+ ec = entrance_cost(y, x, zoc_hash)
next if cost[x]+ec > mob
if not openset.include?(y)
openset.push(y)
@@ -45,29 +47,37 @@ def my_destinations_and_backchains(exclusions = [], from=nil)
end
def my_destinations(exclusions = [], from=nil)
- return destinations # FIXME: temporarily as I'm implementing Zone Of Control
- # http://weewar.wikispaces.com/Zone+of+Control
my_destinations_and_backchains(exclusions, from)[0]
end
-
-
#-- ----------------------------------------------
# Travel
#++
# The cost in movement points for the unit to enter the given Hex. This
# is an internal method used for travel-related calculations; you should not
# normally need to use this yourself.
- def entrance_cost(hex)
- raise "hex is nil" if hex.nil?
+ def entrance_cost(hex, from, zh)
+ raise "hex is nil" if hex.nil?
raise "hex.type is nil" if hex.type.nil?
specs_for_type = Hex.terrain_specs[hex.type]
- raise "** No spec for type '#{hex.type}' hex: #{hex}" if specs_for_type.nil?
- tag(specs_for_type[:movement][unit_class]) { |rv|
- raise "no movement spec for #{unit_class}" if !rv
- }
+ raise "** No spec at all for type '#{hex.type}' from hex: #{hex}" if specs_for_type.nil?
+ rv = specs_for_type[:movement][unit_class]
+ raise "** No movement spec for #{unit_class}" if !rv
+ rv + zoc_cost(hex, from, zh)
+ end
+
+ def self.init_zoc_hash(game)
+ zoc_hash = Hash.new(false)
+ game.enemy_units.each{|e| e.hex.neighbours.each { |n| zoc_hash[n] = true}}
+ zoc_hash
+ end
+
+ def zoc_cost(hex, from, zoc_hash)
+ # if was already in zoc, can not move to hex
+ return 99 if zoc_hash[from] and zoc_hash[hex]
+ return 0
end
# The cost in movement points for the unit to travel along the given path.
@@ -96,7 +106,6 @@ def travel_cost(dest)
#
# best_path = my_trooper.shortest_path(enemy_base)
def shortest_path(dest, exclusions = [])
- exclusions ||= []
reconstruct_path(dest, my_shortest_path(dest, exclusions)) # shortest_paths(exclusions)
end
@@ -117,12 +126,13 @@ def my_shortest_path(goal, exclusions = [])
closedset = exclusions.map{ |x| x} # The set of nodes already evaluated. Perform a copy of the array
openset = [@hex] # The set of tentative nodes to be evaluated, initially containing the start node
came_from = Hash.new # The map of navigated nodes.
+ zoc_hash = Unit.init_zoc_hash(@game)
g_score = Hash.new
h_score = Hash.new
f_score = Hash.new
g_score[@hex] = 0 # Cost from start along best known path.
- h_score[@hex] = heuristic_cost_estimate(@hex, goal.hex)
+ h_score[@hex] = heuristic_cost_estimate(@hex, goal, @hex, zoc_hash)
f_score[@hex] = g_score[@hex] + h_score[@hex] # Estimated total cost from start to goal through y.
while not openset.empty?
@@ -135,7 +145,7 @@ def my_shortest_path(goal, exclusions = [])
openset.delete(x)
closedset.push(x)
- #x.value = "X "
+ #x.value = ". "
#x.map.print_map
for y in x.neighbours
@@ -152,7 +162,7 @@ def my_shortest_path(goal, exclusions = [])
if tentative_is_better
came_from[y] = x
g_score[y] = tentative_g_score
- h_score[y] = heuristic_cost_estimate(y, goal)
+ h_score[y] = heuristic_cost_estimate(y, goal, x, zoc_hash)
f_score[y] = g_score[y] + h_score[y]
end
end
@@ -175,8 +185,8 @@ def dist_between(b)
# end
#end
- def heuristic_cost_estimate(x,y)
- x.dist_between(y) + entrance_cost(x)
+ def heuristic_cost_estimate(x, goal, from, zoc_hash)
+ x.dist_between(goal) + entrance_cost(x, from, zoc_hash)
end
# Calculate all shortest paths from the Unit's current Hex to every other
View
@@ -168,9 +168,9 @@ def can_attack?(target)
# if my_unit.can_reach? the_hex
# my_unit.move_to the_hex
# end
- def can_reach?(hex)
- my_destinations.include? hex
- end
+ #def can_reach?(hex)
+ # my_destinations.include? hex
+ #end
# An Array of the Unit s of the Game which are on the same side as this Unit.
# friends = my_unit.allied_units
@@ -255,22 +255,25 @@ def move_to(destination, options = {})
raise "** options is not a Hash" if options.class.name != "Hash"
command = ""
options[:exclusions] ||= []
+ options[:exclusions] -= [destination]
#puts " destination is #{destination}, #{options[:exclusions].size} exclusions"
moved = false
attacked = false
captured = false
- new_hex = @hex
+ new_hex = @hex
- if destination != @hex #and !dfa_has_target_in_range(destination)
+ if destination != @hex and !dfa_has_target_in_range(destination)
# Travel
-
path = shortest_path(destination, options[:exclusions])
+ # if the destination is occupied, travel one less
+ path.pop if destination.hex.occupied?
+
#puts " path: #{path.join(', ')}"
if !path or path.empty?
$stderr.puts "* No path from #{self} to #{destination}"
else
- dests = my_destinations
+ dests = my_destinations(allied_units)
#puts " dests: #{dests.size}: #{dests.join(', ')}"
new_dest = path.pop
while new_dest and not dests.include?(new_dest)
@@ -567,10 +570,6 @@ def select_near_target()
# TODO: find a safer place anyway (intersection with a best place to attack and a safe place).
# If does not exists, well return best place to attack
def best_place_to_attack(target)
- # FIXME: my_destinations does not take into account the fact that
- # there are surrounding enemies
- # (the movement options are not the same in that case, but I don't know them)
-
# dfas-like can not attack after moving
return @hex if dfa_has_target_in_range(target)
@@ -614,11 +613,7 @@ def insure_paths_to_enemy_bases_not_blocked
end
def move_away_from(units)
- d = my_destinations
- #far_from_unit = farest(unit, @game.units)
- #far_destination = farest(far_from_unit, @game.units)
- #return move_to(far_destination, {:exclusions=>@game.units})
- # TODO: shortest_path takes a unit, bt we pass an hex
+ # TODO: shortest_path takes a unit, but we pass an hex
return move_to(farest(units, @game.units), {:exclusions=>@game.units})
end
Oops, something went wrong.

0 comments on commit 18a952c

Please sign in to comment.