'RTanque' Part 4: Invincible
Making Any Bot a Brain Surgeon.
How to render your opponents brainless.
Brain surgery is not simple, at least not to me. The base brain surgery code for this bot came from a bot David Bock created called the lobotomizer. I am going to show you how you can make any bot a brain surgeon like the lobotomizer by:- Adding an accessor to the Bot class.
- Adding three lines of code to your tick! method.
- Adding two private methods at the end of your code.
class YourBot < RTanque::Bot::Brain NAME = "Your Bot's Name" include RTanque::Bot::BrainHelper TURRET_FIRE_RANGE = RTanque::Heading::ONE_DEGREE * 1.5 def tick! some_function_a some_function_b end def some_function_a #logic of function a end def some_function_b #logic of function b end endFirst we will drill open the skull, by adding the following code.
# drill open their skulls class RTanque::Bot attr_accessor :brain endThis little bit of code reopens the Bot Class and allows you access to That by itself won't make you a brain surgeon but it will allow you to avoid doing brain surgery on your self. We will next edit the tick! of your bot.
def tick! first_time do lobotomize_opponents end some_function_a some_function_b endSo now that you added this code to your bot, we also need to add the functions first_time and lobotimize_opponents that your tick! method will now call at the end of your code.
private def first_time unless @first_time_guard yield @first_time_guard = "checked" end end def lobotomize_opponents ObjectSpace.each_object(RTanque::Bot) { |x| x.brain.class.send(:define_method, :tick!) { "#This is where you write the new tick! #method that you will use to replace your opponents #If you leave this blank or only comments" } unless x.brain.class == self.class } endLet me explain tick! calls first_time every time it runs. When first_time runs for the first time will not @first_time_guard be defined so by default @first_time_guard will be nil.
The unless is basically an if not so when @first_time_guard is evaluated as nil, yield will execute which means lobotomize_opponents will be called, and @first_time_guard will be assigned "checked". When tick! runs again it will still call first_time, but @first_time_guard is not false or nil, so yield will not execute again.
How lobotomize_opponents works is a little more complicated, and I do not fully understand it completely, but basically for every Bot it will redefine tick! to whatever string is inside the inner curly brackets.
unless x.brain.class == self.classThe above code, just makes sure you are not redefining your own bots tick! One important note if you try to make clones of this tank, they're likely to lobotomize each other. Here is what the BasicTargetingBot looks like after I made him a brain surgeon.
class BrainSurgeonBasicTargetingBot < RTanque::Bot::Brain NAME = "#{self}" include RTanque::Bot::BrainHelper TURRET_FIRE_RANGE = RTanque::Heading::ONE_DEGREE * 1.5 # drill open their skulls class RTanque::Bot attr_accessor :brain end def tick! first_time do lobotomize_opponents end ## main logic goes here # use self.sensors to detect things # use self.command to control tank # self.arena contains the dimensions of the arena self.make_circles if we_have_target target = we_have_target track_target(target) aim_at_target(target) fire_at_target(target) else self.scan_with_radar end end def make_circles command.speed = MAX_BOT_SPEED # takes a value between -5 to 5 command.heading = sensors.heading + MAX_BOT_ROTATION end def we_have_target self.nearest_target end def nearest_target self.sensors.radar.min { |a,b| a.distance <=> b.distance } end def track_target(target) self.command.radar_heading = target.heading end def aim_at_target(target) self.command.turret_heading = target.heading end def fire_at_target(target) if self.pointing_at_target?(target) command.fire(MAX_FIRE_POWER) end end def pointing_at_target?(target) (target.heading.delta(sensors.turret_heading)).abs < TURRET_FIRE_RANGE end def scan_with_radar self.command.radar_heading = self.sensors.radar_heading + MAX_RADAR_ROTATION end private def first_time unless @first_time_guard yield @first_time_guard = "checked" end end def lobotomize_opponents ObjectSpace.each_object(RTanque::Bot) { |x| x.brain.class.send(:define_method, :tick!) { "#This is where you write the new tick! #method that you will use to replace your opponents #if you leave this blank you will make him brainless" } unless x.brain.class == self.class } end endThis is a guide to making 'RTanque' tank bot brain surgeons.
This is Part 4 of a 4 part series on 'RTanque' tank bot making. Joshua Kemp @joshuakemp1 and myself Cody Kemp @codesterkemp have be joint authors during this series.
We do foresee writing of future RTanque articles including "How to Avoid Brain Surgery" and "Precision Targeting"
No comments:
Post a Comment