Ruby Warrior + Command Pattern

Written by Bennett on October 26, 2016

For those that haven’t heard about Ruby Warrior, it is a fun interactive game designed to teach you the Ruby programming language. You play as a warrior climbing a tall tower to reach the precious Ruby at the top level. On each floor you need to write a Ruby script to instruct the warrior to battle enemies, rescue captives, and reach the stairs.

When it comes to writing code and accomplishing certain tasks, there is certainly always more than one way to get the job done. With that being said, why not structure your code in a clean, concise way, so that even the most novice of programmers can understand what’s going on.

The Command design pattern is intended to separate and decouple an object of invocation from an object that receives the message, all while encapsulating relevant information of a method that can be stored and executed at a later time.

My First Attempt

My first solution to Ruby Warrior contained nothing but if/else statements. Although it was getting the job done, I started to see how my solution could become very messy and it was getting hard for me to keep track of where I was in the program.


class Player
   def play_turn(warrior)
     if warrior.feel.empty?
       if warrior.health < 15
         warrior.rest!
      else
        warrior.walk!
      end
    else
      warrior.attack!
    end    
  end
end
.......


Using the Command Pattern


To start out, Ruby Warrior gives us this shell code.


class Player
  def play_turn(warrior)
    # your code goes here
  end
end


First we start by creating our InitializeWarrior class. This is the class that all of our new warriors actions will inherit from.



class InitializeWarrior
  def initialize(warrior)
    @warrior = warrior
  end
end



From now on whenever a new warrior action is introduced we’ll put it in a class and that class will inherit from our InitializeWarrior class. In the beginning levels, our warrior is given a handful of new abilities. Our warrior can now walk, attack, rest, check his/her health, and rescue a captive. Once we start creating classes that perform specific tasks, we can start to see a pattern emerging. In keeping with patterns, each of our new classes will only have two methods. A question? method and an action! method.


class Walk < InitializeWarrior
  def question?(health)
     @warrior.feel.empty?
  end

  def action!
    @warrior.walk!
  end
end

class Attack < InitializeWarrior
  def question?(health)
    !@warrior.feel.empty?
  end

  def action!
    @warrior.attack!
  end
end

class WarriorRest < InitializeWarrior
  def question?(health)
   if @warrior.health < 10
     true
   end
  end

  def action!
    @warrior.rest!
  end
end

class WarriorHealth < InitializeWarrior
  def question?(health)
    @warrior.health < 20 && @warrior.health >= health
  end

  def action!
    @warrior.rest!
  end
end

class RescueCaptive < InitializeWarrior
  def question?(health)
    @warrior.feel.captive?
  end

  def action!
    @warrior.rescue!
  end
end


Now that we’ve created separate classes for each warrior action, we need to create new instances of these classes and store them so we can run the commands inside of them. We’ll do this in our play_turn method.



class Player
  def play_turn(warrior)
    # your code goes here

    walk = Walk.new(warrior)
    attack = Attack.new(warrior)
    rest = WarriorRest.new(warrior)
    health = WarriorHealth.new(warrior)
    captive = RescueCaptive.new(warrior)
  end
end



After creating new instances of all of our classes, we still have to run these commands. For this, I created an array called actionarray within the playturn method and I’m going to loop through each of the objects we created.



class Player
  def play_turn(warrior)
    # your code goes here

    walk = Walk.new(warrior)
    attack = Attack.new(warrior)
    rest = WarriorRest.new(warrior)
    health = WarriorHealth.new(warrior)
    captive = RescueCaptive.new(warrior)

    # create an array of warrior actions so we can reuse them when needed
    action_array = [walk, attack, rest health, captive]

    # looping through our action_array in order to run our commands in each separate class
    action_array.each do |item|
      if item.question?(@health)
        item.action!
        break
      end
    end
    @health = warrior.health
  end
end



That’s the Command Pattern in action!

Ending thoughts…

The Command Pattern makes certain that our code is cooperative with open closed design principles, which means we can implement a new command relatively easy. All of our objects that were created perform a specific task and then they are executed by our Player class. Whenever a new warrior action is introduced, all we have to do is create the class and then answer the question? and perform the action! that is necessary to get out code to work.