What are game rules? When browsing the rules of popular games like Monopoly and Scrabble, they seem to follow a similar format:
- The initial conditions of the game (the setup)
- Then given a condition,
- the set of allowable actions for the player to do
- the effects of the condition
class SceneRulesThen I'd be able to call it from the controllers. However, on second thought, it's rather ugly, since I'd be updating the karma everywhere in the controllers. If I understand cross-cutting concerns correctly, scoring karma would be a good example of one. I suppose it's a good candidate for aspect orientated programming, so I scrapped the code above.
def initialize(model)
@scene = model
@user = @scene.submitting_user
end
def on_submit
@user.points += 1
end
end
class SceneshotRules
def initialize(model)
@sceneshot = model
@user = @sceneshot.sceneshot_uploader
end
def on_submit
@user.points += 10
@scene.submitting_user.points += 5
end
end
Logging is often cited as the poster-child problem to solve with AOP. Logging needs to be done everywhere in the code, but it really has nothing to do with the responsibilities of the class that it's performed in. So you have the same code doing the same thing, duplicated everywhere because there's no one place to put it to make things easy to change.
By the same token, game rules and scoring are of the same nature. And because game rules involve lots of different objects at once, and scoring is interspersed throughout, I think that makes it a good candidate for AOP. However, Ruby has no such direct support for AOP. Instead, the closest thing we have are observers, before/after/around filters (in Rails), and some meta-programming.
I wanted something that allowed me to list out rules like games like Monopoly and Scrabble. I'd have a setup, and some conditions and their effects. Scoring is simplified here because the only time you can score is when one of the models is created or changes state. This is a good fit to the observers and the filters available in Rails.
class ScoringRules < ActiveRecord::ObserverHere, the Rules module is what encapsulates the setup, rule, and rule_dispatch calls. I needed setup so that I can access different "game elements" (the board and the players) to update the scoring. It basically stores the setup as a list of lambdas that it can execute at a later time when the rule needs to be executed. Now, when a model is created, we ask the rule dispatcher to figure out which rules execute based on the rules we've named, and then execute the attached block. The block is passed a hash of different game pieces that it needs to update the score and the game conditions. That's it.
observe Sceneshot, Scene
include Rules
setup { :scene => Proc.new { |sceneshot| sceneshot.scene } },
{ :sceneshot_uploader => Proc.new { |sceneshot| sceneshot.sceneshot_uploader },
:scene_submitting_user => Proc.new { |sceneshot| sceneshot.scene.submitting_user } }
rule :after_create_sceneshot do |board, players|
players[:scene_submitting_user].score += 5
end
# put more rules here
def after_create(model)
rule_dispatch(:after_create, model)
end
end
I thought it was an interesting way about it and probably warranted some criticism. Is there any particular disadvantage of doing it this way? And if you can think of a way to not have to explicitly state the model relationships in the setup, that'd be nice. half-tip!