ºÝºÝߣ

ºÝºÝߣShare a Scribd company logo
Learning Ruby with
   RubyWarrior
     Mr. Big Cat
     2011/1/25
About Me
¡ñ   ´ó؈
¡ñ   I like coding
¡ñ   ´ó؈¹²ºÍ‡ø£º http://gaagaaga.blogspot.com
¡ñ   Twitter&Plurk: miaout17
Outline
¡ñ   Introducing RubyWarrior
¡ñ   Playing RubyWarrior
¡ñ   Solving RubyWarrior with Metaprogramming
    and DSL
What is RubyWarrior?
A game designed to teach the Ruby language
and artificial intelligence in a fun, interactive way.
Who created RubyWarrior?




RubyWarrior is created
  by Ryan Bates, the
 author of Railscasts.
Spoiler Warning!!
How to start?
In your shell:


$ gem install rubywarrior
$ rubywarrior




                                 Demo!
How to play?

  Read README and
    Edit Your Script
    Edit Your Script



   Run RubyWarrior


                          No
    Level Passed?


             Yes
 Jump to the next level
   Gain New Abilities          Demo!
What's Within?

      Player         RubyWarrior::Turn

    play_turn              attack!
        ...              detonate!
                          rescue!
                            rest!
                           shoot!
                            walk!
RubyWarrior::Space
                        direction_of
       wall?            distance_of
     enemy?                health
     captive?
     empty?                  feel
      stairs?              listen
     ticking?               look
What's Within?

      Player         RubyWarrior::Turn

    play_turn              attack!
        ...              detonate!
                          rescue!
                            rest!
                           shoot!
                            walk!
RubyWarrior::Space
                        direction_of
       wall?            distance_of
     enemy?                health
     captive?
     empty?                  feel
      stairs?              listen
     ticking?               look
What's Within?

      Player         RubyWarrior::Turn

    play_turn              attack!
        ...              detonate!
                          rescue!
                            rest!
                           shoot!
                            walk!
RubyWarrior::Space
                        direction_of
       wall?            distance_of
     enemy?                health
     captive?
     empty?                  feel
      stairs?              listen
     ticking?               look
What's Within?

      Player         RubyWarrior::Turn

    play_turn              attack!
        ...              detonate!
                          rescue!
                            rest!
                           shoot!
                            walk!
RubyWarrior::Space
                        direction_of
       wall?            distance_of
     enemy?                health
     captive?
     empty?                  feel
      stairs?              listen
     ticking?               look
Epic Mode

       Beginner   Intermediate

       Level 1      Level 1
       Level 2      Level 2
Epic                             Epic
Mode   Level 3      Level 3      Mode
       Level 4      Level 4
       Level 5      Level 5
       Level 6      Level 6
       Level 7      Level 7
       Level 8      Level 8
       Level 9      Level 9

                                  Demo!
My Epic Mode Solution
¡ñ   An AI logic that pass intermediate epic mode
    with all-S rank
¡ñ   Three implementation styles:
    ¡ñ   Naive Solution
    ¡ñ   Pure-OO Solution
    ¡ñ   Metaprogramming&DSL Solution
Naive Solution
DIRS.each do |dir|
  if @warrior.feel(dir).ticking?
    @warrior.rescue!(dir)
    return
  end
end

return if walk_to_ticking!

DIRS.each do |dir|
  if should_detonate?(dir)
    detonate!(dir)
    return
  end
end

DIRS.each do |dir|
  if @warrior.feel(dir).enemy?
    @warrior.attack!(dir)
    return
  end
end

DIRS.each do |dir|
  if @warrior.feel(dir).captive?
    @warrior.rescue!(dir)
    return
  end
end

walk!(direction_of_stairs)


                                      Demo!
Pure OO Solution

                   Demo!
Metaprogramming&DSL Solution
¡ñ   Today we won't focus on how to do
    metaprogramming and create a DSL
¡ñ   We focus on how metaprogramming & DSL
    make our life easier
What's Metaprogramming?
What's Metaprogramming?




"Writing a program that writes programs."
What's Metaprogramming?




"Writing a program that writes programs."
              Á¨ßÖ¹©š¢Ð¡£¿
We use attr_accessor everyday
class Warrior
  attr_accessor :health
end

w = Warrior.new
w.health = 95
puts w.health
What is attr_accessor?
class Warrior                      class Warrior
  attr_accessor :health              def health
end                                    @health
                                     end
w = Warrior.new                      def health=(val)
w.health = 95                          @health = val
puts w.health                        end
                                   end

                                   w = Warrior.new
                                   w.health = 59
                                   puts w.health




                     attr_acccessor is a METHOD!
Getter/Setter in Java
class Warrior
{
  public void setHealth(int val)
  {
    health = val;
  }
  public int getHealth()
  {
    return health;
  }
  private int health;
}

public class AttrAccessor
{
    public static void main(String[] args)
    {
      Warrior s = new Warrior();
      s.setHealth(95);
      System.out.println("Health = " + s.getHealth());
    }
}
Delegation
class Player

 def hurt?
   return false unless @last_health
   return @warrior.health < @last_health
 end

 def play_turn(warrior)
   @warrior = warrior
   if @warrior.feel.captive?
     @warrior.rescue!
   elsif !@warrior.feel.empty?
     @warrior.attack!
   elsif @warrior.health == 20 || hurt?
     @warrior.walk!
   else
     @warrior.rest!
   end
   @last_health = @warrior.health
 end

end
Delegation
class Player                               class Player

 def hurt?                                   def hurt?
   return false unless @last_health            return false unless @last_health
   return @warrior.health < @last_health       return health < @last_health
 end                                         end

 def play_turn(warrior)                      def play_turn(warrior)
   @warrior = warrior                          @warrior = warrior
   if @warrior.feel.captive?                   if feel.captive?
     @warrior.rescue!                            rescue!
   elsif !@warrior.feel.empty?                 elsif !feel.empty?
     @warrior.attack!                            attack!
   elsif @warrior.health == 20 || hurt?        elsif health == 20 || hurt?
     @warrior.walk!                              walk!
   else                                        else
     @warrior.rest!                              rest!
   end                                         end
   @last_health = @warrior.health              @last_health = health
 end                                         end

end                                        end
Delegation
Delegation Implementation
class Player

 def health
   @warrior.health
 end

 def feel
   @warrior.feel
 end

 def rescue!
   @warrior.rescue!
 end

 def attack!
   @warrior.attack!
 end

 def walk!
   @warrior.walk!
 end

 def rest!
   @warrior.rest!
 end
Delegation Implementation
class Player            require 'forwardable'

 def health             class Player
   @warrior.health
 end
                          extend Forwardable
 def feel
   @warrior.feel          def_delegators :@warrior, :health, :feel,
 end                        :rescue!, :attack!, :walk!, :rest!

 def rescue!
   @warrior.rescue!
 end

 def attack!
   @warrior.attack!
 end

 def walk!
   @warrior.walk!
 end

 def rest!
   @warrior.rest!
 end
Domain Specific Language(DSL)
               solution
DIRS.each do |dir|                 require 'player_helper'
  if @warrior.feel(dir).ticking?
    @warrior.rescue!(dir)
    return                         class Player
  end
end
                                     include PlayerHelper
return if walk_to_ticking!

DIRS.each do |dir|                   def_strategries do
  if should_detonate?(dir)             directional(:rescue!, :ticking?)
    detonate!(dir)
                                       strategy { rest! if rest_when_ticking? }
    return
  end                                  directional(:detonate!, :should_detonate?)
end                                    directional(:attack!, :enemy?)
DIRS.each do |dir|
                                       directional(:rescue!, :captive?)
  if @warrior.feel(dir).enemy?         strategy { walk!(direction_of_stairs) }
    @warrior.attack!(dir)            end
    return
  end
end

DIRS.each do |dir|
  if @warrior.feel(dir).captive?                  Player
    @warrior.rescue!(dir)
    return
  end
end
                                            PlayerHelper
walk!(direction_of_stairs)


                                                               Demo!
DSL is Everywhere
¡ñ   Rails Routing

resources :forums, :only => [:index, :show] do
  resources :posts
end

namespace :admin do
  resources :forums do
    resources :posts, :except => [:new, :create]
  end
end
DSL is Everywhere
 ¡ñ   Rake Task

task :drink do
  puts "I drink juice"
end

task :eat do
  puts "I eat sandwich"
end

task :breakfast => [:drink, :eat] do
  puts "I ate breakfast"
end
Conclusion:
                 The Ruby way I know


My RubyWarrior
                             Rails                        Rake
    Script
                                                                    Implementing high-
                                                                    level logic is incredible
   Player                Rails App                      Rake Task   simple with easy-to-
                                                                    use API and DSL


                            Rails
                                                                    Write API and create
                   ActiveRecord         ActionMailer                DSL with
PlayerHelper                                              Rake      metaprogramming
                   ActionPack           ActiveSupport               techniques

                                  ...
Lecture martial
¡ñ   Source code is available on github
    https://github.com/gaagaaga/warrior-tuesday
    ¡ñ   i-naive
    ¡ñ   i-oo
    ¡ñ   i-dsl
    ¡ñ   dsl-starter
¡ñ   ºÝºÝߣ will be on slideshare (coming soon)
Learning Resource
¡ñ   For Beginners:
    ¡ñ   TryRuby: http://tryruby.org/
    ¡ñ   RubyWarrior: https://github.com/ryanb/ruby-warrior
    ¡ñ   The Ruby Programming Language (Book)
¡ñ   For Intermediate:
    ¡ñ   Eloquent Ruby (Book)
    ¡ñ   Metaprogramming Ruby (Book)
Any Question?

More Related Content

Learning Ruby with RubyWarrior

  • 1. Learning Ruby with RubyWarrior Mr. Big Cat 2011/1/25
  • 2. About Me ¡ñ ´ó؈ ¡ñ I like coding ¡ñ ´ó؈¹²ºÍ‡ø£º http://gaagaaga.blogspot.com ¡ñ Twitter&Plurk: miaout17
  • 3. Outline ¡ñ Introducing RubyWarrior ¡ñ Playing RubyWarrior ¡ñ Solving RubyWarrior with Metaprogramming and DSL
  • 4. What is RubyWarrior? A game designed to teach the Ruby language and artificial intelligence in a fun, interactive way.
  • 5. Who created RubyWarrior? RubyWarrior is created by Ryan Bates, the author of Railscasts.
  • 7. How to start? In your shell: $ gem install rubywarrior $ rubywarrior Demo!
  • 8. How to play? Read README and Edit Your Script Edit Your Script Run RubyWarrior No Level Passed? Yes Jump to the next level Gain New Abilities Demo!
  • 9. What's Within? Player RubyWarrior::Turn play_turn attack! ... detonate! rescue! rest! shoot! walk! RubyWarrior::Space direction_of wall? distance_of enemy? health captive? empty? feel stairs? listen ticking? look
  • 10. What's Within? Player RubyWarrior::Turn play_turn attack! ... detonate! rescue! rest! shoot! walk! RubyWarrior::Space direction_of wall? distance_of enemy? health captive? empty? feel stairs? listen ticking? look
  • 11. What's Within? Player RubyWarrior::Turn play_turn attack! ... detonate! rescue! rest! shoot! walk! RubyWarrior::Space direction_of wall? distance_of enemy? health captive? empty? feel stairs? listen ticking? look
  • 12. What's Within? Player RubyWarrior::Turn play_turn attack! ... detonate! rescue! rest! shoot! walk! RubyWarrior::Space direction_of wall? distance_of enemy? health captive? empty? feel stairs? listen ticking? look
  • 13. Epic Mode Beginner Intermediate Level 1 Level 1 Level 2 Level 2 Epic Epic Mode Level 3 Level 3 Mode Level 4 Level 4 Level 5 Level 5 Level 6 Level 6 Level 7 Level 7 Level 8 Level 8 Level 9 Level 9 Demo!
  • 14. My Epic Mode Solution ¡ñ An AI logic that pass intermediate epic mode with all-S rank ¡ñ Three implementation styles: ¡ñ Naive Solution ¡ñ Pure-OO Solution ¡ñ Metaprogramming&DSL Solution
  • 15. Naive Solution DIRS.each do |dir| if @warrior.feel(dir).ticking? @warrior.rescue!(dir) return end end return if walk_to_ticking! DIRS.each do |dir| if should_detonate?(dir) detonate!(dir) return end end DIRS.each do |dir| if @warrior.feel(dir).enemy? @warrior.attack!(dir) return end end DIRS.each do |dir| if @warrior.feel(dir).captive? @warrior.rescue!(dir) return end end walk!(direction_of_stairs) Demo!
  • 17. Metaprogramming&DSL Solution ¡ñ Today we won't focus on how to do metaprogramming and create a DSL ¡ñ We focus on how metaprogramming & DSL make our life easier
  • 19. What's Metaprogramming? "Writing a program that writes programs."
  • 20. What's Metaprogramming? "Writing a program that writes programs." Á¨ßÖ¹©š¢Ð¡£¿
  • 21. We use attr_accessor everyday class Warrior attr_accessor :health end w = Warrior.new w.health = 95 puts w.health
  • 22. What is attr_accessor? class Warrior class Warrior attr_accessor :health def health end @health end w = Warrior.new def health=(val) w.health = 95 @health = val puts w.health end end w = Warrior.new w.health = 59 puts w.health attr_acccessor is a METHOD!
  • 23. Getter/Setter in Java class Warrior { public void setHealth(int val) { health = val; } public int getHealth() { return health; } private int health; } public class AttrAccessor { public static void main(String[] args) { Warrior s = new Warrior(); s.setHealth(95); System.out.println("Health = " + s.getHealth()); } }
  • 24. Delegation class Player def hurt? return false unless @last_health return @warrior.health < @last_health end def play_turn(warrior) @warrior = warrior if @warrior.feel.captive? @warrior.rescue! elsif !@warrior.feel.empty? @warrior.attack! elsif @warrior.health == 20 || hurt? @warrior.walk! else @warrior.rest! end @last_health = @warrior.health end end
  • 25. Delegation class Player class Player def hurt? def hurt? return false unless @last_health return false unless @last_health return @warrior.health < @last_health return health < @last_health end end def play_turn(warrior) def play_turn(warrior) @warrior = warrior @warrior = warrior if @warrior.feel.captive? if feel.captive? @warrior.rescue! rescue! elsif !@warrior.feel.empty? elsif !feel.empty? @warrior.attack! attack! elsif @warrior.health == 20 || hurt? elsif health == 20 || hurt? @warrior.walk! walk! else else @warrior.rest! rest! end end @last_health = @warrior.health @last_health = health end end end end
  • 27. Delegation Implementation class Player def health @warrior.health end def feel @warrior.feel end def rescue! @warrior.rescue! end def attack! @warrior.attack! end def walk! @warrior.walk! end def rest! @warrior.rest! end
  • 28. Delegation Implementation class Player require 'forwardable' def health class Player @warrior.health end extend Forwardable def feel @warrior.feel def_delegators :@warrior, :health, :feel, end :rescue!, :attack!, :walk!, :rest! def rescue! @warrior.rescue! end def attack! @warrior.attack! end def walk! @warrior.walk! end def rest! @warrior.rest! end
  • 29. Domain Specific Language(DSL) solution DIRS.each do |dir| require 'player_helper' if @warrior.feel(dir).ticking? @warrior.rescue!(dir) return class Player end end include PlayerHelper return if walk_to_ticking! DIRS.each do |dir| def_strategries do if should_detonate?(dir) directional(:rescue!, :ticking?) detonate!(dir) strategy { rest! if rest_when_ticking? } return end directional(:detonate!, :should_detonate?) end directional(:attack!, :enemy?) DIRS.each do |dir| directional(:rescue!, :captive?) if @warrior.feel(dir).enemy? strategy { walk!(direction_of_stairs) } @warrior.attack!(dir) end return end end DIRS.each do |dir| if @warrior.feel(dir).captive? Player @warrior.rescue!(dir) return end end PlayerHelper walk!(direction_of_stairs) Demo!
  • 30. DSL is Everywhere ¡ñ Rails Routing resources :forums, :only => [:index, :show] do resources :posts end namespace :admin do resources :forums do resources :posts, :except => [:new, :create] end end
  • 31. DSL is Everywhere ¡ñ Rake Task task :drink do puts "I drink juice" end task :eat do puts "I eat sandwich" end task :breakfast => [:drink, :eat] do puts "I ate breakfast" end
  • 32. Conclusion: The Ruby way I know My RubyWarrior Rails Rake Script Implementing high- level logic is incredible Player Rails App Rake Task simple with easy-to- use API and DSL Rails Write API and create ActiveRecord ActionMailer DSL with PlayerHelper Rake metaprogramming ActionPack ActiveSupport techniques ...
  • 33. Lecture martial ¡ñ Source code is available on github https://github.com/gaagaaga/warrior-tuesday ¡ñ i-naive ¡ñ i-oo ¡ñ i-dsl ¡ñ dsl-starter ¡ñ ºÝºÝߣ will be on slideshare (coming soon)
  • 34. Learning Resource ¡ñ For Beginners: ¡ñ TryRuby: http://tryruby.org/ ¡ñ RubyWarrior: https://github.com/ryanb/ruby-warrior ¡ñ The Ruby Programming Language (Book) ¡ñ For Intermediate: ¡ñ Eloquent Ruby (Book) ¡ñ Metaprogramming Ruby (Book)