Upload
yc-ling
View
3.073
Download
2
Embed Size (px)
DESCRIPTION
My presentation at Ruby Tuesday Taiwan #16
Citation preview
Learning Ruby withRubyWarrior
Mr. Big Cat2011/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?
Demo!
Edit Your ScriptEdit Your ScriptRead README and
Edit Your Script
Run RubyWarrior
Jump to the next levelGain New Abilities
Level Passed?
No
Yes
What's Within?
Player
play_turn...
wall?enemy?captive?empty?stairs?ticking?
RubyWarrior::Space
RubyWarrior::Turn
attack!detonate!rescue!
rest!shoot!walk!
direction_ofdistance_of
health
feellistenlook
What's Within?
Player
play_turn...
wall?enemy?captive?empty?stairs?ticking?
RubyWarrior::Space
RubyWarrior::Turn
attack!detonate!rescue!
rest!shoot!walk!
direction_ofdistance_of
health
feellistenlook
What's Within?
Player
play_turn...
wall?enemy?captive?empty?stairs?ticking?
RubyWarrior::Space
RubyWarrior::Turn
attack!detonate!rescue!
rest!shoot!walk!
direction_ofdistance_of
health
feellistenlook
What's Within?
Player
play_turn...
wall?enemy?captive?empty?stairs?ticking?
RubyWarrior::Space
RubyWarrior::Turn
attack!detonate!rescue!
rest!shoot!walk!
direction_ofdistance_of
health
feellistenlook
Epic Mode
Demo!
Level 1
Level 2
Level 3
Level 4
Level 5
Level 6
Level 7
Level 8
Level 9
Level 1
Level 2
Level 3
Level 4
Level 5
Level 6
Level 7
Level 8
Level 9
Beginner Intermediate
EpicMode
EpicMode
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 SolutionDIRS.each do |dir| if @warrior.feel(dir).ticking? @warrior.rescue!(dir) return endend
return if walk_to_ticking!
DIRS.each do |dir| if should_detonate?(dir) detonate!(dir) return endend
DIRS.each do |dir| if @warrior.feel(dir).enemy? @warrior.attack!(dir) return endend
DIRS.each do |dir| if @warrior.feel(dir).captive? @warrior.rescue!(dir) return endend
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 :healthend
w = Warrior.neww.health = 95puts w.health
What is attr_accessor?
class Warrior attr_accessor :healthend
w = Warrior.neww.health = 95puts w.health
class Warrior def health @health end def health=(val) @health = val endend
w = Warrior.neww.health = 59puts 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 [email protected]? @warrior.attack! elsif @warrior.health == 20 || hurt? @warrior.walk! else @warrior.rest! end @last_health = @warrior.health end
end
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 [email protected]? @warrior.attack! elsif @warrior.health == 20 || hurt? @warrior.walk! else @warrior.rest! end @last_health = @warrior.health end
end
class Player
def hurt? return false unless @last_health return health < @last_health end
def play_turn(warrior) @warrior = warrior if feel.captive? rescue! elsif !feel.empty? attack! elsif health == 20 || hurt? walk! else rest! end @last_health = health 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
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
require 'forwardable'
class Player
extend Forwardable
def_delegators :@warrior, :health, :feel, :rescue!, :attack!, :walk!, :rest!
Domain Specific Language(DSL) solution
DIRS.each do |dir| if @warrior.feel(dir).ticking? @warrior.rescue!(dir) return endend
return if walk_to_ticking!
DIRS.each do |dir| if should_detonate?(dir) detonate!(dir) return endend
DIRS.each do |dir| if @warrior.feel(dir).enemy? @warrior.attack!(dir) return endend
DIRS.each do |dir| if @warrior.feel(dir).captive? @warrior.rescue!(dir) return endend
walk!(direction_of_stairs)
require 'player_helper'
class Player
include PlayerHelper
def_strategries do directional(:rescue!, :ticking?) strategy { rest! if rest_when_ticking? } directional(:detonate!, :should_detonate?) directional(:attack!, :enemy?) directional(:rescue!, :captive?) strategy { walk!(direction_of_stairs) } end
Demo!
PlayerHelper
Player
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
Rails
ActiveRecord ActionMailer
ActionPack ActiveSupport
...
PlayerHelper
Player Rails App Rake Task
Rake
My RubyWarrior Script Rails Rake
Implementing high-level logic is incredible simple with easy-to-use API and DSL
Write API and create DSL with metaprogramming techniques
Lecture martial
● Source code is available on githubhttps://github.com/gaagaaga/warrior-tuesday● i-naive● i-oo● i-dsl● dsl-starter
● Slide 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?