#Here the attributes (or data) and methods (or behaviours) for each object are defined
  
#Population is defined as an array which will hold the "individuals" objects
class Population < Array
  alias_method :old_init, :initialize
    def initialize(num = 0, val = nil, &proc)
      if block_given?
	num.times {|i| self.push (yield i)}
      else
	old_init(num, val)
end
end
end

#This is the individual
class Individual

  #The various attributes for each individual animal are assigned
  # they are variables that hold:
  
  # alive (=1) or dead (alive = 0)
  # pregnant (mother = 1) or barren (mother = 0)
  # the age of the animal (continuous integer, ages)
  # disease status (infected = 0 or 1)
 
  attr_writer :sex, :alive, :mother, :ages, :infected
  def initialize(sex, alive = 1,mother = 0, ages=0, infected=0)
  @sex = sex
  @alive = alive
  @mother = mother
  @ages = ages
  @infected = infected
end

#This just tells the computer what to do if I call a "puts" (= print)
def to_s
"Sex: #{@sex} Alive: #{@alive} Pregnant: #{@mother} Age: #{@ages} Infected: #{@infected}\n "
end

# I defined the exp function here
def exp(num)
  (2.71828182845904523536)**num
end
  
# these are accessor functions that allow the main portion of the program
# to access individual object's attributes:

def sex
	@sex
end


def alive
  @alive
end


def mother
  @mother
end

def ages
  @ages
end

def infected
  @infected
end

#These are the various methods or behaviours that each critter can do:

#Choose sex
def chooseSex
	if rand < 0.5
		@sex = "M"
	else
		@sex = "F"
	end
end


# Get infected (McCarty infection probability function)

def infect(n,nInfectious)
	r = rand
	p = 1-(1-1/n)**(nInfectious*2)
	if @infected ==0
		  if r < p 
		  @infected = 1
		  else
		  @infected = 0
		  end
	elsif @infected ==1 #These are animals that have been infected, but in a latent state for one year
		r1 = rand
		if r1 < 0.09
			@infected = 2 #Stay latent
		elsif (r1 >= 0.09) and (r1 < 0.99)
			@infected=3 #Become infectious
		else
			@infected = 7 #Dead
		end
	elsif @infected == 2 #These have been latent for one year
		if rand < 0.9
			@infected = 4 #become infectious
		else
			@infected=7 #die
		end
	elsif @infected == 3 #these are infectious 
		if rand < 0.955
			@infected = 7 #these are dead
		else
			@infected = 5
		end
	elsif @infected >= 4
		@infected = 7
	end
end


#Disease status- and age-specific survival curve (Siler model - lx is the survivorship)
def survive

if @sex == "M"
	lx1= exp(-0*(1-exp(-9*@ages))-0.329*@ages-0.00017*(exp(2*@ages)-1)) 
	lx2= exp(-0*(1-exp(-9*(@ages+1)))-0.329*(@ages+1)-0.00017*(exp(2*(@ages+1))-1)) 
	sx=lx2/lx1  
	if @infected ==7
		@alive = 0
	else
		if rand>sx
			@alive = 0
		else
			@alive = 1
		  end
	end
elsif @sex == "F" 
	lx1= exp(-0.01*(1-exp(-9*@ages))-0.158*@ages-0*(exp(2*@ages)-1)) 
	lx2= exp(-0.01*(1-exp(-9*(@ages+1)))-0.158*(@ages+1)-0.000*(exp(2*(@ages+1))-1)) 
	sx=lx2/lx1  
	if @infected ==7
		@alive = 0
	else
		if rand>sx
			@alive = 0
		else
			@alive = 1
		  end
	end
end


end

#Reproduction curve (age independent above 2, but a function of pop size)

def reproduce(n)
if @sex == "F"
	if @ages > 1
		if rand>exp(2.5-0.005*n)/(1+exp(2.5-0.005*n))
		@mother = 0
		else
		@mother = 1
		end
	else
		@mother= 0
	end
else
	@mother = 0
end
	
end  

#This ages each animal

def age
  @ages+=1
end


end

#******************************************************************************
#This is the main portion of the model


# Number of time steps
t = 50

#Initial pop size


males= Population.new(250) {Individual.new("M",1,0,3,0)}
females = Population.new(250) {Individual.new("F",1,0,3,0)}
n = 500.0


population = []
population = males + females


#Here you enter the initial number of infected critters:
4.times {population< 1
		mums += 1
	end
	}


if n < 1000
	mult = 2 - 0.0000018*(n**2)
	babies = mums*mult
	babies = Integer(babies)
end
	
	

#A new array is created to hold the new babies
	newBabies = Population.new(babies) {Individual.new("N",1,0,0,0)}

#Choose sex
	newBabies.each { |member|
	      member.chooseSex
	   }

#And then is added to the population array
	population = population + newBabies



#Infect critters
population.each { |member|
      member.infect(n,nInfectious)
   }

  
#Determine if critters are going to die    

population.each { |member|
      member.survive
    }

#Delete dead critters
population.delete_if{|member|
member.alive ==0}

#Age critters
population.each { |member|
      member.age
    }
    

#Count live critters

n = 0.0
population.each { |member|
  if member.alive == 1
    n= n+1
  end
  }

#Count infected critters
nInfected = 0.0
population.each { |member|
if member.infected > 1
    nInfected = nInfected+1
  end
}

#Count infectious critters
nInfectious = 0.0
population.each { |member|
if member.infected >= 3
    nInfectious = nInfectious+1
  end
}



#Here, the data are put into storage arrays:
popSize[i] = n
numberInfected[i]=nInfected
numberInfectious[i]=nInfectious

#Just prints stuff to the screen:
#puts "Year no. #{i}"
#puts population
puts "Time: #{i} Number infectious: #{nInfectious} Number infected: #{nInfected} Population size: #{n}"



end #here ends the time loop

#Now the data are sent to files
results = File.new("results", "w")
results.puts popSize
results.close 

infectedResults = File.new("infectedresults", "w")
infectedResults.puts numberInfected
infectedResults.close 

infectiousResults = File.new("infectiousresults", "w")
infectiousResults.puts numberInfectious
infectiousResults.close 

finalAge = File.new("finalAge", "w")
finalAge.puts population
finalAge.close 

puts "--PRESS ENTER TO CONTINUE--"
fun = gets

#******************************************************************************

    Source: geocities.com/do_joly