前提
完善工具的前提是先要了解工具,建议先看一遍ant.rb里的内容,了解他实现了哪些数据接口。
当然如果仔细看过官方的教程的话,会发现教程所使用的python和java的库的功能比ruby的强大很多。
没关系,我们这就来丰满手里的工具。
主要接口介绍
Ant类
Ant类是描述单个蚂蚁的类,主要方法是def order direction
。命令蚂蚁下一回合走的方向,direction参数为方向('E','S','W','N')。后续会对该方法进行封装。
Square类
描述了地图上每一个格子的类。用于各种判断地形的操作。主要的方法是def neighbor direction
,探测临近点的信息。
AI类
这个类很难描述,只能从一些特征上描述,每回合都会刷新内容。
和MyBot.rb中的描述类似
ai.setup do |ai|
# 执行初始化内容
end
ai.run do |ai|
# 执行一回合的动作
end
动手完善工具
需要一个公共库,来放置一些类似调试日志、计算距离等功能的方法。计算距离是每个蚂蚁安排命令优先级最基本的功能,因此我们先用这两个功能做例子。
创建公共库
创建utils.rb:
module Utils
# For ordering ant
def spherical_distance(loc_a, loc_b, row_max, col_max)
vertical_side = if (loc_a.row - loc_b.row).abs > row_max/2
row_max - (loc_a.row - loc_b.row).abs
else
(loc_a.row - loc_b.row).abs
end
horizontal_side = if (loc_a.col - loc_b.col).abs > col_max/2
col_max - (loc_a.col - loc_b.col).abs
else
(loc_a.col - loc_b.col).abs
end
Math.hypot(vertical_side, horizontal_side)
end
# For calculating vision
def straight_distance(loc_a, loc_b)
Math.hypot(loc_a.col - loc_b.col, loc_a.row - loc_b.row)
end
class Logger
attr_accessor :logfile
def initialize(file)
@logfile = file
end
def info message
message ||= "nil"
file_stream = File.new(@logfile, "a")
file_stream.write("[" + Time.now.strftime("%Y-%m-%d %H:%M:%S") + "]" + message.to_s + "\n")
file_stream.close
end
end
end
spherical_distance
和straight_distance
使用Math.hypot
计算两点之间的直线距离。spherical_distance
因为地图是类似球面到了边界,可以从另一边出现(虽然视野是不能跨边界的)。而straight_distance
直线距离计算是用来判断视野的(在ants.rb
中有see?
方法。
增加Ant类功能
增加了distance
方法后,就可以对Ant类进行一些扩展,偷懒直接就在里面ants.rb里加代码了。
...
class Ant
...
def see?(loc)
distance(@square, loc) <= @ai.viewradius
end
def towards(dir)
@square.neighbor dir
end
def inspect
"<Row #{@square.row}, Col #{@square.col}>"
end
end
...
see?(loc)
方法判断蚂蚁的可是范围,toward(dir)
对临近的格子的方法作语义更通畅的封装。
增加Square类功能
ants.rb
...
class Square
...
# Returns true if this square is my hill, false if not
def my_hill?; @hill && @hill == 0; end
# Returns true if this square is enemy hill, false if not
def enemy_hill?; @hill && @hill != 0; end
...
def occupied?
water? || food? || ant? || my_hill?
end
def inspect
"<Row #{@row}, Col #{@col}>"
end
增加AI类功能
为了在setup阶段能获取到地图,给后续初始化未探索区域,调整map的位置
class AI
...
def setup
...
@map=Array.new(@rows){|row| Array.new(@cols){|col| Square.new false, false, false, nil, row, col, self } }
yield self
@stdout.puts 'go'
@stdout.flush
@did_setup=true
end
再增加获取地图上资源的方法:地图上可视范围内食物、敌方巢穴、我方巢穴等。
class AI
...
def foods
@map.flatten.select(&:food?)
end
def enemy_hills
@map.flatten.select { |square| square.hill? && !square.my_hill? }
end
def my_ants_in_hill
self.my_ants.select { |ant| ant.square.hill? }
end
def my_hills
@map.flatten.select { |square| square.hill? && square.my_hill? }
end
...
end