# Patrick Coleman # Comp Sys Res - 6th period - 2007-08 # Sugarscape - agent require 'environment.rb' class Agent #x-position, y-position, amount of sugar possessed, true if agent is dead, number time steps agent has been alive #color (red or blue) of the agent attr_accessor :posX, :posY, :wealth, :dead, :age, :color #Initializes variables based on location and random values def initialize (posX, posY, env=@@env, emptylocs=@@emptylocs) @posX = posX @posY = posY #Copy of environment shared by each agent object @@env = env @@emptylocs = emptylocs #Tells location an agent is there @@env[posY][posX].hasAgent= true #Initial random amount of sugar @wealth = rand(30) #Rate at which an agent consumes sugar @metabolism = 1 + rand(4) #Amount of spaces an agent can see in the environment @vision = 1 + rand(6) #Agent is alive @dead = false #Sets agent's starting age and at what age it will die @age = 0 @ageLim = 1500 + rand(500) #Agent is randomly red or blue @color = rand(2) end #Moves, harvests sugar at that location, and consumes sugar def act #Age is incremented and agent dies if it has reached age limit @age += 1 if @age == @ageLim @dead = true return end #Original location no longr has agent @@env[@posY][@posX].hasAgent= -1 #Checks locations, picks direction of best one, and moves in that direction move #Tells the location it has an agent @@env[@posY][@posX].hasAgent= @color #Adds harvested sugar to wealth @wealth += @@env[@posY][@posX].harvest #Consumes sugar from the amount of sugar possessed @wealth -= @metabolism #Agent dies if it does not have enough sugar to consume @dead = true if @wealth < 0 end def move @@emptylocs[[@posY,@posX]] = 0 #Possible locations choices = [nil,nil,nil,nil] #Choices are invalid if there is an agent in the neighboring location choices[0] = [@@env[@posY+1][@posX],-1,0] if @posY+1 < @@env.length and @@env[@posY+1][@posX].hasAgent == -1 choices[1] = [@@env[@posY-1][@posX],-1,0] if @posY-1 >= 0 and @@env[@posY-1][@posX].hasAgent == -1 choices[2] = [@@env[@posY][@posX+1],-1,0] if @posX+1 < @@env.length and @@env[@posY][@posX+1].hasAgent == -1 choices[3] = [@@env[@posY][@posX-1],-1,0] if @posX-1 >= 0 and @@env[@posY][@posX-1].hasAgent == -1 #Choices are also invalid if they don't follow Schelling segregation rules for i in 0...4 do choices[i] = nil if !validNeighbor(choices[i]) end #Returns if no moves are valid return if choices == [nil,nil,nil,nil] #Looks out as far as vision permits in each of the four cardinal directions #Stores the adjacent location in that direction, the max sugar quantity, and the distance to the max sugar for k in 1..@vision do break if choices[0] == nil break if @posY+k >= @@env.length if @@env[@posY+k][@posX].sugarquant > choices[0][1] choices[0] = [@@env[@posY+1][@posX],@@env[@posY+k][@posX].sugarquant,@vision-k] end end for k in 1..@vision do break if choices[1] == nil break if @posY-k < 0 if @@env[@posY-k][@posX].sugarquant > choices[1][1] choices[1] = [@@env[@posY-1][@posX],@@env[@posY-k][@posX].sugarquant,@vision-k] end end for k in 1..@vision do break if choices[2] == nil break if @posX+k >= @@env.length if @@env[@posX+k][@posX].sugarquant > choices[2][1] choices[2] = [@@env[@posY][@posX+1],@@env[@posY][@posX+k].sugarquant,@vision-k] end end for k in 1..@vision do break if choices[3] == nil break if @posX-k >= @@env.length if @@env[@posX-k][@posX].sugarquant > choices[3][1] choices[3] = [@@env[@posY][@posX-1],@@env[@posY][@posX-k].sugarquant,@vision-k] end end #Removes nil choices and sorts choices = choices.compact choices.sort! {|x,y| y[1] <=> x[1]} #Removes locations with less sugar than the best location while !(choices[-1][1] == choices[0][1] and choices[-1][-1] == choices[0][-1]) choices.pop end #Randomly picks a location of the best one or more possible ones i = rand(choices.length) return if choices[i][0] == nil @posX = choices[i][0].posX @posY = choices[i][0].posY @@emptylocs.delete([@posY,@posX]) end #Returns false if 1/2 or more neighbors are of opposite color def validNeighbor loc return false if loc == nil count = 0 px = loc[0].posX py = loc[0].posY pxp = true if px+1 < @@env.length pxm = true if px-1 >= 0 pyp = true if py+1 < @@env.length pym = true if py-1 >= 0 nghbr = false count += 1 if pyp and @@env[py+1][px].hasAgent == (@color+1)%2 count += 1 if pyp and pxp and @@env[py+1][px+1].hasAgent == (@color+1)%2 count += 1 if pyp and pxm and @@env[py+1][px-1].hasAgent == (@color+1)%2 count += 1 if pym and @@env[py-1][px].hasAgent == (@color+1)%2 count += 1 if pym and pxp and @@env[py-1][px+1].hasAgent == (@color+1)%2 count += 1 if pym and pxm and @@env[py-1][px-1].hasAgent == (@color+1)%2 count += 1 if pxp and @@env[py][px+1].hasAgent == (@color+1)%2 count += 1 if pxm and @@env[py][px-1].hasAgent == (@color+1)%2 nghbr = true if count > 0 count -= 1 if pyp and @@env[py+1][px].hasAgent == @color count -= 1 if pyp and pxp and @@env[py+1][px+1].hasAgent == @color count -= 1 if pyp and pxm and @@env[py+1][px-1].hasAgent == @color count -= 1 if pym and @@env[py-1][px].hasAgent == @color count -= 1 if pym and pxp and @@env[py-1][px+1].hasAgent == @color count -= 1 if pym and pxm and @@env[py-1][px-1].hasAgent == @color count -= 1 if pxp and @@env[py][px+1].hasAgent == @color count -= 1 if pxm and @@env[py][px-1].hasAgent == @color return true if !nghbr return false if count >= 0 return true end end