Skip to content

Instantly share code, notes, and snippets.

@pasberth
Created February 10, 2012 12:43
Show Gist options
  • Save pasberth/1789427 to your computer and use it in GitHub Desktop.
Save pasberth/1789427 to your computer and use it in GitHub Desktop.
かなり雑だけど張っておく 擬似的な生態系を作ってみる
# -*- coding: utf-8 -*-
module Ecosys
extend self
class FoodWeb
def initialize
@creatures = []
@mutual = []
end
attr_reader :creatures
attr_reader :mutual
def inspect
@creatures.map do |c|
filter(c).map(&:inspect).join "\n"
end.join "\n\n#{'='*40}\n"
end
def << creature
add_creature creature
add_mutual creature
creature
end
def filter c, d=nil
r = @mutual.select { |m| m.c == c or m.d == c }
return r if d.nil?
r.select { |m| m.c == d or m.d == d }
end
def changed c
# 絶滅
if c.n <= 0
@creatures.delete c
@mutual.delete_if do |m|
m.c == c or m.d == c
end
end
end
def add_mutual c
@creatures.each do |d|
if c.descent.nil?
@mutual << Mutual.new(c, d, Effect.friend)
next
end
# 近縁の種であれば共生を選択する
if c == d or c.descent == d or c.descent.ascents.include? d
@mutual << Mutual.new(c, d, Effect.friend)
next
end
# 近隣の種でなくなったら性質をランダムに変更する
if c.descent.descent.nil? or c.descent.descent == d or c.descent.descent.ascents.include? d
@mutual << Mutual.new(c, d, Effect.sample)
next
end
desm = c.descent.mutualof d
if desm.nil?
@mutual << Mutual.new(c, d, Effect.sample) # 通常ここは処理されない
elsif rand(4) == 0
@mutual << Mutual.new(c, d, Effect.sample) # 一部の性質は変化する
else
@mutual << Mutual.new(c, d, desm.effect) # 基本的には親の性質を受け継ぐ
end
end
end
def add_creature c
@creatures << c
end
private :add_mutual, :add_creature
class Effect
def initialize text, &action
@text = text
@action = action
end
def call *a, &b
@action.call *a, &b
end
def to_s
@text
end
def to_proc
@action
end
FRIEND = Effect.new "they are friend." do |c, d|
if [true, false].sample then
c.n -= 1
c.food_web.changed c
d.breed
else
d.n -= 1
d.food_web.changed d
c.breed
end
end
def self.friend
[FRIEND].sample
end
LEFT_EAT = Effect.new "left eat right" do |c, d|
c.eat d
end
RIGHT_EAT = Effect.new "right eat left" do |c, d|
d.eat c
end
SYMBIOSIS = Effect.new "symbiosis" do |c, d|
c.breed
d.breed
end
def self.sample
[LEFT_EAT, RIGHT_EAT, SYMBIOSIS].sample
end
end
class Mutual
def initialize c, d, effect
@c = c
@d = d
@effect = effect
end
attr_reader :c, :d
attr_reader :effect
def call
effect.call c, d
end
def inspect
"#{@c}, #{@d}; #{@effect}"
end
def to_proc
method(:call).to_proc
end
end
end
class Creature
NAMES = [
'ar', 'af', 'dor', 'imd', 'rus', 'wa', 'fa', 'wi', 'mma', 'be', 'ry', 'jara', 'je'
]
def initialize descent=nil, n=1
@n = 1
if descent.nil?
@descent = nil
@name = ''
@name_words = []
@food_web = FoodWeb.new
@food_web << self
return
end
@descent = descent
if descent.name_words.length > 6
[descent.name_words[1..-1], NAMES.sample].tap do |oldn, newn|
@name = oldn.join + newn
@name_words = oldn + [newn]
end
else
NAMES.sample.tap do |newn|
@name = descent.name + newn
@name_words = descent.name_words + [newn]
end
end
@food_web = descent.food_web
@food_web << self
end
def eat other
other.n -= 1
breed
food_web.changed other
food_web.changed self
self
end
def breed
if rand(7) > 0 # 1/7 で進化
self.n += 1
self
else
create
end
end
def create
Creature.new self
end
def ascents
@food_web.creatures.select do |c|
c.descent == self
end
end
def mutualof d
@food_web.filter(self, d).first
end
def to_s
inspect
end
def inspect
"<#[#{@n}]: #{@name} from #{@descent.name if @descent}:C>"
end
attr_accessor :n
attr_reader :name, :name_words
attr_reader :descent
attr_reader :food_web
end
end
# -*- coding: utf-8 -*-
require './ecosys'
include Ecosys
common_descent = Creature.new nil, 10
# 最初の生物を生み出す
5.times do
a = Creature.new common_descent, 10
4.times do
b = Creature.new a, 10
5.times do
c = Creature.new b, 10
end
end
end
food_web = common_descent.food_web
c = 100
loop do
food_web.mutual.sample.call
c -= 1
if c < 0
c = 100
puts "="*40
puts food_web.creatures.join "\n"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment