Rubyでわかるマギカ世界の魔法少女システム論
「まどか☆マギカから考えるメカニズムデザイン」も合わせてご参照ください。
class Hope attr_reader :value def initialize(value) @initial_value = value @value = value value_changed end def add(value) @value += value value_changed end def despair @value = - @initial_value end def value_changed=(block) @on_value_changed = block end def value_changed @on_value_changed.call(self) if @on_value_changed end end class Human def initialize h = Hope.new(10) h.value_changed = ->(hope) do check_hope end self.singleton_class.class_eval do define_method :hope do h end end end def check_hope end def to_s "Human:#{object_id}" end end class QB private_class_method :new def self.generate @qb ||= new end def sign(girl, contract) girl.singleton_class.class_eval do include Magica end contract.call(girl) end module Magica def use_magic hope.add(-1) end def give_hope(person, value) hope.add(-value) person.hope.add(value) end def check_hope become_witch unless hope.value > 0 end def become_witch self.singleton_class.class_eval do include Witch end hope.despair freeze end def to_s "Magica:#{object_id}" end end module Witch def scatter_despair(person) person.add_hope(-person.hope.value) end def self.included(mod) mod.freeze end def to_s "Witch:#{object_id}" end end end qb = QB.generate all_magica = [] 100.times do magica = Human.new qb.sign(magica, ->(magica){}) 10.times{ magica.use_magic } all_magica << magica end madoka = Human.new all_magica << madoka qb.sign(madoka, ->(girl) do QB::Magica.class_eval do define_method :check_hope do if hope.value < 0 girl.give_hope(self, -hope.value) freeze end end end all_magica.each do |m| if m.hope.value < 0 girl.give_hope(m, -m.hope.value) end end end)
少し補足
- singleton_classは特異クラスを返します
- includeは不可逆です
- QBはシングルトンパターンに従いました
- このプログラムは無限再帰します。