This week has gone by fast.
I have accomplished a lot this week, unfortunately it wasn't all software development. Only 14.25 hours of it was was software development.
A bit short of my goal. I don't have my next weeks goals setup yet. The original business model for my website won't work out so i will have to make some adjustments. I am going to have a planning session on Monday afternoon and finish this blog post's details.
Ruby on rails, weekly round up.
RTanque: Article # 5 "How to Avoid Brain Surgery"
How to Avoid Brain Surgery
Changing how your bot thinks.
Scalpel, forceps, knife, screwdriver... ...the brain surgeon keeps operating on the patient until, with a sense of surprise he realizes. Oops, there is no patient here! Now in real life that would never happen, but in this world of RTanque that is what can happen, and I am going to show you how you modify any bot to avoid brain surgery. All you need to do is redefine one method in brain, so that we can rename the tick! method. That way when the brain surgeon replaces your tick! method it won't matter because your not using that function to think any longer. So your bots tick! function will look something like this before we rename it.def tick! some_function_a some_function_b end
Which we will rewrite to say
def some_hard_to_guess_name some_function_a some_function_b end
So now that you made this change your bots code, we also need to redefine the function in brain that calls tick! The name of this function is tick. What we will do is define the tick function in our code so that it will override the one in brain. the tick method in brain looks like this.
def tick(sensors) self.sensors = sensors RTanque::Bot::Command.new.tap do |empty_command| self.command = empty_command self.tick! end end
Put the whole function in your bot's code, and then we change self.tick! to self.some_hard_to_guess_name like this.
def tick(sensors) self.sensors = sensors RTanque::Bot::Command.new.tap do |empty_command| self.command = empty_command self.some_hard_to_guess_name end end
Let me explain what is going on. the tick function in the brain normally calls tick! but now because we define it locally, the local function will override the one built into the brain, and now call the some_hard_to_guess_name function. One important note: if you add this code to a brains surgeon bot you can now make make clones of your tank without your clones lobotomizing each other.
Here is what the BrainSurgeonBasicTargetingBot looks like after I added this feature.
class CloneableBrainSurgeonBasicTargetingBot < 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(sensors) self.sensors = sensors RTanque::Bot::Command.new.tap do |empty_command| self.command = empty_command self.some_hard_to_guess_name end end def some_hard_to_guess_name 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 end class DroidSurgeon < CloneableBrainSurgeonBasicTargetingBot NAME = "#{self}" end
With this tank not only will you be protected from brain surgery, but you will also lobotomize all the other tanks in the field including the lobotimizer, if they have not taken similar steps to defend their brains.
Easter, Breaking 300, and the End of Class
My Weekly Agenda Goals
- Publish 2 RTanque Articles
- Finish the bonus videos from class and the one lecture on deployment and security.
- Spend at Least 6 hours on the Michael Hartl's Ruby on Rails Tutorial.
- Create a mockup of what I want the Job application site to look like.
- Interview 3 local business owners on
'RTanque' Part 4: Invincible
'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"
Crank Out RTanque Tutorials
This week has been good overall, I logged 22.5 hours of study time this week. Josh and I have published two tutorials together this week and written a third, that Josh will publish shortly on his blog. We will finish writing and I will publish the fourth tutorial this week on my blog. I had originally thought the final tutorial would cover an advanced targeting topic, dealing with smart targeting and avoiding shooting your allies. But instead we decided to cover a tutorial about using meta programming to disable your enemies. Unfortunatly while I really did crank out tutorials I slacked off and didn't complete the rest of my Weekly Agenda goals. This is being posted on Monday so I am a little late on publication, but still pretty close. My new Weekly Agenda Goals are: Watch all unwatched lecture videos. Complete hw 2 for class. Complete the the last quiz for the class. Finish writing the part 4 of the tutorial series.
Beginner's guide to 'RTanque' Part:2
The Attack of the Clones
This guide covers how to make a tank bot army in a single file with 'RTanque'
Now that you all have seen how to build a basic tank, We are going to see how to create a bunch of clones in the same file first we start with a single BasicBotclass BasicBot < RTanque::Bot::Brain NAME = 'basic_bot' include RTanque::Bot::BrainHelper def tick! ## 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 self.command.fire(0.25) end def make_circles command.speed = MAX_BOT_SPEED # takes a value between -5 to 5 command.heading = sensors.heading + 0.01 end endfirst we copy and paste the whole BasicBot and paste it below the original and run it. Unfortunatley there is still only one bot. The problem is the class's both have the same name. So we change the second class name to Clone1 Now when we run it there will be two tanks. This is marvolous, but lets see if we can DRY up this code a little. Lets cut out all the logic for Clone1 so we have
class Clone1 < RTanque::Bot::Brain endWhen we run it again we still have two tanks but one is just sitting there still as death. The problem is Clone1's Brain doesn't have any logic. We solve that problem by letting Clone1 inherit BasicBot's Brain with
class Clone1 < BasicBot endNow here is my code for a basic_bot_swarm
class BasicBot < RTanque::Bot::Brain NAME = "#{self}" include RTanque::Bot::BrainHelper def tick! ## 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 self.command.fire(MIN_FIRE_POWER) end def make_circles command.speed = MAX_BOT_SPEED # takes a value between -5 to 5 command.heading = sensors.heading + MAX_BOT_ROTATION end end class Clone1 < BasicBot NAME = "#{self}" end class Clone2 < BasicBot NAME = "#{self}" end class Clone3 < BasicBot NAME = "#{self}" end class Clone4 < BasicBot NAME = "#{self}" end class Clone5 < BasicBot NAME = "#{self}" end class Clone6 < BasicBot NAME = "#{self}" endThis is an extremely basic, easy guide to making 'RTanque' tank bot clones. If you are looking to make your tank smarter, you'll want to see part 3, when we will deal with the subject of targeting.
This is Part 2 of a 4 part series on 'RTanque' tank bot making. Joshua Kemp @joshuakemp1 and myself Cody Kemp @codesterkemp will be joint authors during this series.
RTanque and the Tank Wars
This past week has been great, I finished homework 1 part 2 in three hours, However I am still having trouble with homework 1 part 1, which I have completed, except for the ability to successfully transfer the comments from the one to the other without losing them. I am troubled by the autograder, not agreeing with my manual tests, but maybe I'll be able to sort it out easier when I have completely finished the assignment. I watched most of the two previous weeks of video lectures. I pushed up some more of chapter 3 from Michael Hartl's Rails Tutorial. I also spent a great deal of time trying to create the 'super' tank in rtanque. Study hours this week was at 26.5 hours, bringing my grand total to 263.25 hours. Pair programed and went to a programming Meetup.
The two Agenda goals that really did not happen, were watching last weeks video lectures and make significant progress in the Uno game. I have set the Uno game on the back burner while I crank out these RTanque Tutorials. I might even try to throw in a short screencast.
My Agenda Goals for this week.
Complete Homework 1 part 1.
Catch up on watching the lecture videos.
Finish pushing up chapter 3 of Michael Hartl Rails Tutorial app.
Crank out these RTanque Tutorials.
So here again are my Weekly Basic Goals.
Pair program at least once a week.
Study a minimum of 21 hours a week.
Publish my weekly blog by the end of Sunday.
Share it on Twitter