RubyWarrior is a game designed to teach the Ruby programming language and artificial intelligence concepts in a fun way. Players write Ruby scripts to control a warrior avatar to complete levels by solving puzzles and battling enemies. The game was created by Ryan Bates to be both entertaining and educational for learning Ruby. It teaches concepts like object-oriented programming, metaprogramming, and domain-specific languages through gameplay. The document provides examples of different approaches for solving levels, from a naive solution to ones using pure object-orientation, metaprogramming, and domain-specific languages.
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
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)