Skip to content

Instantly share code, notes, and snippets.

@popey456963
Created May 2, 2017 11:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save popey456963/d3a721cc1cf755b9fef077f9e4e66979 to your computer and use it in GitHub Desktop.
Save popey456963/d3a721cc1cf755b9fef077f9e4e66979 to your computer and use it in GitHub Desktop.
Wikibooks Solutions
#Skeleton Program code for the AQA A Level Paper 1 2017 examination
#this code should be used in conjunction with the Preliminary Material
#written by the AQA Programmer Team
#developed in the Python 3.4.1 programming environment
# Enumerate over a class
import enum
# Contains functions to generate random numbers, pick a random item from
# an array, etc.
import random
# Contains mathematical functions
import math
class Location:
"""
Description: Stores the number of warrens and foxes in a location.
Args: Details of what a location contains
Returns: Details of what a location contains
"""
def __init__(self):
self.Fox = None
self.Warren = None
class Simulation:
"""
Description: Class to hold the running of the simulation.
Args: LandscapeSize (Int), InitialWarrenCount (Int), InitialFoxCount (Int),
Variability (Int), FixedInitialLocations (Bool)
Returns:
"""
def __init__(self, LandscapeSize, InitialWarrenCount, InitialFoxCount, Variability, FixedInitialLocations):
# Set private attributes of class
self.__ViewRabbits = ""
self.__TimePeriod = 0
self.__WarrenCount = 0
self.__FoxCount = 0
self.__ShowDetail = False
self.__LandscapeSize = LandscapeSize
self.__Variability = Variability
self.__FixedInitialLocations = FixedInitialLocations
self.__Landscape = []
# For every row...
for Count1 in range (self.__LandscapeSize):
LandscapeRow = []
# For every cell...
for Count2 in range (self.__LandscapeSize):
# Create landscape object
LandscapeLocation = None
# Write it to the landscape
LandscapeRow.append(LandscapeLocation)
# Add row to environment
self.__Landscape.append(LandscapeRow)
# Call the function to create the landscape
self.__CreateLandscapeAndAnimals(InitialWarrenCount, InitialFoxCount, self.__FixedInitialLocations)
# Draw the landscape on the screen
self.__DrawLandscape()
# Defaults the menu option to 0
MenuOption = 0
# Main simulation loop
while (self.__WarrenCount > 0 or self.__FoxCount > 0) and MenuOption != 5:
print()
print("1. Advance to next time period showing detail")
print("2. Advance to next time period hiding detail")
print("3. Inspect fox")
print("4. Inspect warren")
print("5. Exit")
print()
# Get the user's inupt for the menu choice
MenuOption = int(input("Select option: "))
if MenuOption == 1:
# Advance to next time period showing detail
self.__TimePeriod += 1
self.__ShowDetail = True
self.__AdvanceTimePeriod()
if MenuOption == 2:
# Advance to the next time period without showing detail
self.__TimePeriod += 1
self.__ShowDetail = False
self.__AdvanceTimePeriod()
if MenuOption == 3:
# Inspect fox
x = self.__InputCoordinate("x")
y = self.__InputCoordinate("y")
# If there is a fox there
if not self.__Landscape[x][y].Fox is None:
self.__Landscape[x][y].Fox.Inspect()
if MenuOption == 4:
# Inspect a warren
x = self.__InputCoordinate("x")
y = self.__InputCoordinate("y")
# If a warren exists at the location
if not self.__Landscape[x][y].Warren is None:
# Look at the warren
self.__Landscape[x][y].Warren.Inspect()
self.__ViewRabbits = input("View individual rabbits (y/n)? ")
if self.__ViewRabbits == "y":
# If user wishes to view individual rabbits, list all rabbits there.
self.__Landscape[x][y].Warren.ListRabbits()
# Pause the program until user input
input()
# Get a coordinate from the user.
def __InputCoordinate(self, CoordinateName):
Coordinate = int(input(" Input " + CoordinateName + " coordinate:"))
return Coordinate
# Go to the next time period
def __AdvanceTimePeriod(self):
NewFoxCount = 0
if self.__ShowDetail:
# Add a new line if we're showing more details
print()
# For each x tile on the landscape
for x in range (0, self.__LandscapeSize):
# For each y tile on the landscape
for y in range (0, self.__LandscapeSize):
# If there is a warren there
if not self.__Landscape[x][y].Warren is None:
# If the user wants detail
if self.__ShowDetail:
# Output details
print("Warren at (", x, ",", y, "):", sep = "")
print(" Period Start: ", end = "")
# Inspect warren
self.__Landscape[x][y].Warren.Inspect()
# If there are foxes
if self.__FoxCount > 0:
# Make the fox eat the rabbits in the warren
self.__FoxesEatRabbitsInWarren(x, y)
# If a warren needs to be created
if self.__Landscape[x][y].Warren.NeedToCreateNewWarren():
# Create a new warren
self.__CreateNewWarren()
# Advance a generation in the warren
self.__Landscape[x][y].Warren.AdvanceGeneration(self.__ShowDetail)
# If the user wanted to see details
if self.__ShowDetail:
# Show dat shizzle
print(" Period End: ", end = "")
self.__Landscape[x][y].Warren.Inspect()
input()
# If the warren has dies out
if self.__Landscape[x][y].Warren.WarrenHasDiedOut():
# Delete the warren
self.__Landscape[x][y].Warren = None
# And reduce the warren counter by 1
self.__WarrenCount -= 1
# For every row...
for x in range (0, self.__LandscapeSize):
# For every cell...
for y in range (0, self.__LandscapeSize):
# If there's a fox...
if not self.__Landscape[x][y].Fox is None:
if self.__ShowDetail:
# If we're showing detail, print the line.
print("Fox at (", x, ",", y, "): ", sep = "")
# Advance the generation of the fox.
self.__Landscape[x][y].Fox.AdvanceGeneration(self.__ShowDetail)
# Is the fox dead now?
if self.__Landscape[x][y].Fox.CheckIfDead():
# We kill the fox, and decrement the fox count.
self.__Landscape[x][y].Fox = None
self.__FoxCount -= 1
else:
# Is the fox having a children this turn?
if self.__Landscape[x][y].Fox.ReproduceThisPeriod():
if self.__ShowDetail:
print(" Fox has reproduced. ")
# Incrememnt the fox count.
NewFoxCount += 1
if self.__ShowDetail:
# Inspect the fox.
self.__Landscape[x][y].Fox.Inspect()
# If the fox gave birth, reset current food.
self.__Landscape[x][y].Fox.ResetFoodConsumed()
# If there were any foxes born this turn and we're showing details, print
# the information.
if NewFoxCount > 0:
if self.__ShowDetail:
print("New foxes born: ")
# Create any new foxes
for f in range (0, NewFoxCount):
self.__CreateNewFox()
# Wait for user to press enter before continuing
if self.__ShowDetail:
input()
# Draw the new landscape
self.__DrawLandscape()
print()
# Add all warrens, squares and foxes to the landscape
def __CreateLandscapeAndAnimals(self, InitialWarrenCount, InitialFoxCount, FixedInitialLocations):
for x in range (0, self.__LandscapeSize):
for y in range (0, self.__LandscapeSize):
# For every cell, set it to be a Location() class
self.__Landscape[x][y] = Location()
# Hardcode the warren locations if we're fixing the initial locations.
if FixedInitialLocations:
self.__Landscape[1][1].Warren = Warren(self.__Variability, 38)
self.__Landscape[2][8].Warren = Warren(self.__Variability, 80)
self.__Landscape[9][7].Warren = Warren(self.__Variability, 20)
self.__Landscape[10][3].Warren = Warren(self.__Variability, 52)
self.__Landscape[13][4].Warren = Warren(self.__Variability, 67)
self.__WarrenCount = 5
self.__Landscape[2][10].Fox = Fox(self.__Variability)
self.__Landscape[6][1].Fox = Fox(self.__Variability)
self.__Landscape[8][6].Fox = Fox(self.__Variability)
self.__Landscape[11][13].Fox = Fox(self.__Variability)
self.__Landscape[12][4].Fox = Fox(self.__Variability)
self.__FoxCount = 5
else:
# If we're not fixing locations, add InitialWarrenCount warrens and
# InitialFoxCount foxes.
for w in range (0, InitialWarrenCount):
self.__CreateNewWarren()
for f in range (0, InitialFoxCount):
self.__CreateNewFox()
# Create a new warren in a random location.
def __CreateNewWarren(self):
# Set the warren location to be a random location.
x = random.randint(0, self.__LandscapeSize - 1)
y = random.randint(0, self.__LandscapeSize - 1)
while not self.__Landscape[x][y].Warren is None:
# If that location already has something in it, change the location until
# we that's no longer the case
x = random.randint(0, self.__LandscapeSize - 1)
y = random.randint(0, self.__LandscapeSize - 1)
if self.__ShowDetail:
# If we're showing details, tell the user we created a warren.
print("New Warren at (", x, ",", y, ")", sep = "")
# Create a new warren in the specified location with the defined variability.
self.__Landscape[x][y].Warren = Warren(self.__Variability)
self.__WarrenCount += 1
# Function to create new Fox
def __CreateNewFox(self):
# Get random x location
x = random.randint(0, self.__LandscapeSize - 1)
# Get random y location
y = random.randint(0, self.__LandscapeSize - 1)
# While there is a fox there
while not self.__Landscape[x][y].Fox is None:
# Make some new locations
x = random.randint(0, self.__LandscapeSize - 1)
y = random.randint(0, self.__LandscapeSize - 1)
# If the user requested details
if self.__ShowDetail:
# Print the details
print(" New Fox at (", x, ",", y, ")", sep = "")
# Add a fox object to the fox attribute of the tile
self.__Landscape[x][y].Fox = Fox(self.__Variability)
# Add a fox to the count
self.__FoxCount += 1
# Simulate a fox eating all the rabbits within a warren.
def __FoxesEatRabbitsInWarren(self, WarrenX, WarrenY):
# Get the amoutn of rabbits in a warren
RabbitCountAtStartOfPeriod = self.__Landscape[WarrenX][WarrenY].Warren.GetRabbitCount()
# For every fox...
for FoxX in range(0, self.__LandscapeSize):
for FoxY in range (0, self.__LandscapeSize):
if not self.__Landscape[FoxX][FoxY].Fox is None:
# Find the distance from the warren
Dist = self.__DistanceBetween(FoxX, FoxY, WarrenX, WarrenY)
# If under 3.5 squares away, eat 20% of rabbits.
if Dist <= 3.5:
PercentToEat = 20
# If under 7 squares away, eat 10% of rabbits.
elif Dist <= 7:
PercentToEat = 10
else:
PercentToEat = 0
# Calculate the number of rabbits to kill
RabbitsToEat = int(round(float(PercentToEat * RabbitCountAtStartOfPeriod / 100)))
# Tell the warren that we're eating a specific number of rabbits from it.
FoodConsumed = self.__Landscape[WarrenX][WarrenY].Warren.EatRabbits(RabbitsToEat)
# Give the food to the fox class.
self.__Landscape[FoxX][FoxY].Fox.GiveFood(FoodConsumed)
# If we're being verbose, display this action.
if self.__ShowDetail:
print(" ", FoodConsumed, " rabbits eaten by fox at (", FoxX, ",", FoxY, ").", sep = "")
# Gets the distance between 2 tiles
def __DistanceBetween(self, x1, y1, x2, y2):
return math.sqrt((pow(x1 - x2, 2) + pow(y1 - y2, 2)))
# Render the landscape
def __DrawLandscape(self):
# Output the time
print()
print("TIME PERIOD:", self.__TimePeriod)
print()
print(" ", end = "")
for x in range (0, self.__LandscapeSize):
# Print the top row of numbers
if x < 10:
print("~", end = "")
print(x, "|", end = "", sep="~")
print()
# Print dashed line
for x in range (0, self.__LandscapeSize * 4 + 3):
print("-", end = "")
print()
for y in range (0, self.__LandscapeSize):
if y < 10:
print(" ", end = "")
print("", y, "|", sep = "", end = "")
for x in range (0, self.__LandscapeSize):
if not self.__Landscape[x][y].Warren is None:
if self.__Landscape[x][y].Warren.GetRabbitCount() < 10:
print(" ", end = "")
print(self.__Landscape[x][y].Warren.GetRabbitCount(), end = "")
else:
print(" ", end = "")
if not self.__Landscape[x][y].Fox is None:
print("F", end = "")
else:
print(" ", end = "")
print("|", end = "")
print()
# Class for warrens
class Warren:
# Warren can be defined with an initial RabbitCount (int) and Variability (int)
def __init__(self, Variability, RabbitCount = 0):
# Set the attributes of the class to be the defaults or arguments given
self.__MAX_RABBITS_IN_WARREN = 99
self.__RabbitCount = RabbitCount
self.__PeriodsRun = 0
self.__AlreadySpread = False
self.__Variability = Variability
self.__Rabbits = []
# Create an array which contains a None item for each rabbit in max rabbits.
for Count in range(0, self.__MAX_RABBITS_IN_WARREN):
self.__Rabbits.append(None)
# If rabbit number was not specified, calculate a random warren size.
if self.__RabbitCount == 0:
self.__RabbitCount = int(self.__CalculateRandomValue(int(self.__MAX_RABBITS_IN_WARREN / 4), self.__Variability))
# For each rabbit in the warren, create a rabbit and append it to the Rabbits array.
for r in range (0, self.__RabbitCount):
self.__Rabbits[r] = Rabbit(self.__Variability)
# Start with 25% of max rabbits in the warren, remove some percentage of this number,
# equal to the variability. Then, add upto two times the variability percentage of
# rabbits.
def __CalculateRandomValue(self, BaseValue, Variability):
return BaseValue - (BaseValue * Variability / 100) + (BaseValue * random.randint(0, Variability * 2) / 100)
def GetRabbitCount(self):
return self.__RabbitCount
def NeedToCreateNewWarren(self):
if self.__RabbitCount == self.__MAX_RABBITS_IN_WARREN and not self.__AlreadySpread:
self.__AlreadySpread = True
return True
else:
return False
def WarrenHasDiedOut(self):
if self.__RabbitCount == 0:
return True
else:
return False
def AdvanceGeneration(self, ShowDetail):
self.__PeriodsRun += 1
if self.__RabbitCount > 0:
self.__KillByOtherFactors(ShowDetail)
if self.__RabbitCount > 0:
self.__AgeRabbits(ShowDetail)
if self.__RabbitCount > 0 and self.__RabbitCount <= self.__MAX_RABBITS_IN_WARREN:
if self.__ContainsMales():
self.__MateRabbits(ShowDetail)
if self.__RabbitCount == 0 and ShowDetail:
print(" All rabbits in warren are dead")
def EatRabbits(self, RabbitsToEat):
DeathCount = 0
if RabbitsToEat > self.__RabbitCount:
RabbitsToEat = self.__RabbitCount
while DeathCount < RabbitsToEat:
RabbitNumber = random.randint(0, self.__RabbitCount - 1)
if not self.__Rabbits[RabbitNumber] is None:
self.__Rabbits[RabbitNumber] = None
DeathCount += 1
self.__CompressRabbitList(DeathCount)
return RabbitsToEat
def __KillByOtherFactors(self, ShowDetail):
DeathCount = 0
for r in range (0, self.__RabbitCount):
if self.__Rabbits[r].CheckIfKilledByOtherFactor():
self.__Rabbits[r] = None
DeathCount += 1
self.__CompressRabbitList(DeathCount)
if ShowDetail:
print(" ", DeathCount, "rabbits killed by other factors.")
def __AgeRabbits(self, ShowDetail):
DeathCount = 0
for r in range (0, self.__RabbitCount):
self.__Rabbits[r].CalculateNewAge()
if self.__Rabbits[r].CheckIfDead():
self.__Rabbits[r] = None
DeathCount += 1
self.__CompressRabbitList(DeathCount)
if ShowDetail:
print(" ", DeathCount, "rabbits die of old age.")
def __MateRabbits(self, ShowDetail):
Mate = 0
Babies = 0
for r in range (0, self.__RabbitCount):
if self.__Rabbits[r].IsFemale() and self.__RabbitCount + Babies < self.__MAX_RABBITS_IN_WARREN:
Mate = random.randint(0, self.__RabbitCount - 1)
while Mate == r or self.__Rabbits[Mate].IsFemale():
Mate = random.randint(0, self.__RabbitCount - 1)
CombinedReproductionRate = (self.__Rabbits[r].GetReproductionRate() + self.__Rabbits[Mate].GetReproductionRate()) / 2
if CombinedReproductionRate >= 1:
self.__Rabbits[self.__RabbitCount + Babies] = Rabbit(self.__Variability, CombinedReproductionRate)
Babies += 1
self.__RabbitCount = self.__RabbitCount + Babies
if ShowDetail:
print(" ", Babies, "baby rabbits born.")
def __CompressRabbitList(self, DeathCount):
if DeathCount > 0:
ShiftTo = 0
ShiftFrom = 0
while ShiftTo < self.__RabbitCount - DeathCount:
while self.__Rabbits[ShiftFrom] is None:
ShiftFrom += 1
if ShiftTo != ShiftFrom:
self.__Rabbits[ShiftTo] = self.__Rabbits[ShiftFrom]
ShiftTo += 1
ShiftFrom += 1
self.__RabbitCount = self.__RabbitCount - DeathCount
def __ContainsMales(self):
Males = False
for r in range (0, self.__RabbitCount):
if not self.__Rabbits[r].IsFemale():
Males = True
return Males
def Inspect(self):
print("Periods Run", self.__PeriodsRun, "Size", self.__RabbitCount)
def ListRabbits(self):
if self.__RabbitCount > 0:
for r in range (0, self.__RabbitCount):
self.__Rabbits[r].Inspect()
class Animal:
_ID = 1
def __init__(self, AvgLifespan, AvgProbabilityOfDeathOtherCauses, Variability):
self._NaturalLifespan = int(AvgLifespan * self._CalculateRandomValue(100, Variability) / 100)
self._ProbabilityOfDeathOtherCauses = AvgProbabilityOfDeathOtherCauses * self._CalculateRandomValue(100, Variability) / 100
self._IsAlive = True
self._ID = Animal._ID
self._Age = 0
Animal._ID += 1
def CalculateNewAge(self):
self._Age += 1
if self._Age >= self._NaturalLifespan:
self._IsAlive = False
def CheckIfDead(self):
return not self._IsAlive
def Inspect(self):
print(" ID", self._ID, "", end = "")
print("Age", self._Age, "", end = "")
print("LS", self._NaturalLifespan, "", end = "")
print("Pr dth", round(self._ProbabilityOfDeathOtherCauses, 2), "", end = "")
def CheckIfKilledByOtherFactor(self):
if random.randint(0, 100) < self._ProbabilityOfDeathOtherCauses * 100:
self._IsAlive = False
return True
else:
return False
def _CalculateRandomValue(self, BaseValue, Variability):
return BaseValue - (BaseValue * Variability / 100) + (BaseValue * random.randint(0, Variability * 2) / 100)
class Fox(Animal):
def __init__(self, Variability):
self.__DEFAULT_LIFE_SPAN = 7
self.__DEFAULT_PROBABILITY_DEATH_OTHER_CAUSES = 0.1
super(Fox, self).__init__(self.__DEFAULT_LIFE_SPAN, self.__DEFAULT_PROBABILITY_DEATH_OTHER_CAUSES, Variability)
self.__FoodUnitsNeeded = int(10 * self._CalculateRandomValue(100, Variability) / 100)
self.__FoodUnitsConsumedThisPeriod = 0
def AdvanceGeneration(self, ShowDetail):
if self.__FoodUnitsConsumedThisPeriod == 0:
self._IsAlive = False
if ShowDetail:
print(" Fox dies as has eaten no food this period.")
else:
if self.CheckIfKilledByOtherFactor():
self._IsAlive = False
if ShowDetail:
print(" Fox killed by other factor.")
else:
if self.__FoodUnitsConsumedThisPeriod < self.__FoodUnitsNeeded:
self.CalculateNewAge()
if ShowDetail:
print(" Fox ages further due to lack of food.")
self.CalculateNewAge()
if not self._IsAlive:
if ShowDetail:
print(" Fox has died of old age.")
def ResetFoodConsumed(self):
self.__FoodUnitsConsumedThisPeriod = 0
def ReproduceThisPeriod(self):
REPRODUCTION_PROBABILITY = 0.25
if random.randint(0, 100) < REPRODUCTION_PROBABILITY * 100:
return True
else:
return False
def GiveFood(self, FoodUnits):
self.__FoodUnitsConsumedThisPeriod = self.__FoodUnitsConsumedThisPeriod + FoodUnits
def Inspect(self):
super(Fox, self).Inspect()
print("Food needed", self.__FoodUnitsNeeded, "", end = "")
print("Food eaten", self.__FoodUnitsConsumedThisPeriod, "", end = "")
print()
class Genders(enum.Enum):
Male = 1
Female = 2
class Rabbit(Animal):
def __init__(self, Variability, ParentsReproductionRate = 1.2):
self.__DEFAULT_LIFE_SPAN = 4
self.__DEFAULT_PROBABILITY_DEATH_OTHER_CAUSES = 0.05
super(Rabbit, self).__init__(self.__DEFAULT_LIFE_SPAN, self.__DEFAULT_PROBABILITY_DEATH_OTHER_CAUSES, Variability)
self.__ReproductionRate = ParentsReproductionRate * self._CalculateRandomValue(100, Variability) / 100
if random.randint(0, 100) < 50:
self.__Gender = Genders.Male
else:
self.__Gender = Genders.Female
def Inspect(self):
super(Rabbit, self).Inspect()
print("Rep rate", round(self.__ReproductionRate, 1), "", end = "")
if self.__Gender == Genders.Female:
print("Gender Female")
else:
print("Gender Male")
def IsFemale(self):
if self.__Gender == Genders.Female:
return True
else:
return False
def GetReproductionRate(self):
return self.__ReproductionRate
def Main():
MenuOption = 0
while MenuOption != 3:
print("Predator Prey Simulation Main Menu")
print()
print("1. Run simulation with default settings")
print("2. Run simulation with custom settings")
print("3. Exit")
print()
MenuOption = int(input("Select option: "))
if MenuOption == 1 or MenuOption == 2:
if MenuOption == 1:
LandscapeSize = 15
InitialWarrenCount = 5
InitialFoxCount = 5
Variability = 0
FixedInitialLocations = True
else:
LandscapeSize = int(input("Landscape Size: "))
InitialWarrenCount = int(input("Initial number of warrens: "))
InitialFoxCount = int(input("Initial number of foxes: "))
Variability = int(input("Randomness variability (percent): "))
FixedInitialLocations = False
Sim = Simulation(LandscapeSize, InitialWarrenCount, InitialFoxCount, Variability, FixedInitialLocations)
input()
if __name__ == "__main__":
Main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment