summaryrefslogtreecommitdiff
path: root/wator.py
diff options
context:
space:
mode:
Diffstat (limited to 'wator.py')
-rwxr-xr-xwator.py403
1 files changed, 403 insertions, 0 deletions
diff --git a/wator.py b/wator.py
new file mode 100755
index 0000000..ec215f3
--- /dev/null
+++ b/wator.py
@@ -0,0 +1,403 @@
+#!/usr/bin/python
+
+#
+# Written by Casimo
+# 6th October 2013
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import pygame
+import random
+import argparse
+from pygame.locals import *
+
+# Some constants
+GREEN = (0, 255, 0)
+BLUE = (0, 0, 255)
+BLACK = (0, 0, 0)
+WHITE = (255, 255, 255)
+
+EMPTY = 0
+FISH = 1
+SHARK = 2
+
+DIR_UP = 0
+DIR_RIGHT = 1
+DIR_DOWN = 2
+DIR_LEFT = 3
+
+# Init random and pygame
+random.seed()
+pygame.init()
+
+# Small function to generate an empty map
+def clearmap(maprect):
+ worldmap = []
+ for j in range(maprect[0]):
+ worldmap.append([])
+ for i in range(maprect[1]):
+ worldmap[j].append(0)
+ return worldmap
+
+#--------------------------------------------
+# Creature class
+#--------------------------------------------
+# The creature is a subclass of fish and sharks
+# it includes definitions on how to move, draw and grow
+class Creature(object):
+ # init the creature
+ def __init__(self, race, color, breedtime, width, height):
+ self.x = 0
+ self.y = 0
+ self.race = race
+ self.color = color
+ self.breedtime = breedtime
+ self.age = 0
+ self.width = width
+ self.height = height
+
+ # set the position on the map
+ def locate(self, worldmap, pos):
+ self.x = pos[0]
+ self.y = pos[1]
+
+ if worldmap[self.x][self.y] != EMPTY:
+ return False
+ else:
+ worldmap[self.x][self.y] = self.race
+ return True
+
+ # Draw a rectangle on the surface in the creature's color
+ def draw(self, surface, zoom):
+ pygame.draw.rect(surface, self.color, (self.x * zoom, self.y * zoom, zoom, zoom))
+
+ # returns the position after moving in direction
+ def getpos(self, direction):
+ if direction == DIR_UP:
+ newy = self.y - 1
+ newx = self.x
+ elif direction == DIR_RIGHT:
+ newx = self.x + 1
+ newy = self.y
+ elif direction == DIR_DOWN:
+ newy = self.y + 1
+ newx = self.x
+ elif direction == DIR_LEFT:
+ newx = self.x - 1
+ newy = self.y
+
+ # if the creature goes to the top/bottom/left/right, move it to the other edge
+ if newx == -1:
+ newx = self.width - 1
+ elif newx == self.width:
+ newx = 0
+
+ if newy == -1:
+ newy = self.height - 1
+ elif newy == self.height:
+ newy = 0
+
+ return (newx, newy)
+
+ # moves the creature to the new position and returns (in case of the shark) whether it has eaten a fish
+ def swim(self, worldmap, direction):
+ newpos = self.getpos(direction)
+
+ oldfield = worldmap[newpos[0]][newpos[1]]
+
+ # set the new position in the map
+ worldmap[newpos[0]][newpos[1]] = self.race
+ worldmap[self.x][self.y] = EMPTY
+ self.x = newpos[0]
+ self.y = newpos[1]
+
+ return oldfield
+
+ # returns the creature at the position of the field in direction
+ def check(self, worldmap, direction):
+ newpos = self.getpos(direction)
+
+ return worldmap[newpos[0]][newpos[1]]
+
+ # advance it in age and return true if it's old enough to breed
+ def grow(self):
+ self.age += 1
+ if self.age == self.breedtime:
+ self.age = 0
+ return True
+ else:
+ return False
+
+#-----------------------------------------------------------------------
+# Fish class
+#-----------------------------------------------------------------------
+# The fish class is part of the world
+# it defines the corpus' definitions for a fish
+class Fish(Creature):
+ # init the corpus with the given values
+ #def __init__(self, width, height, color, breedtime):
+ #self.corpus = Creature(FISH, color, breedtime, width, height)
+
+ # swim checks for empty fields
+ def swim(self, worldmap):
+ # get a list of all empty fields
+ normdir = []
+ for j in range(4):
+ if super(Fish, self).check(worldmap, j) == EMPTY:
+ normdir.append(j)
+
+ # and choose a random direction
+ if len(normdir) == 0:
+ # the fish cannot move
+ return False
+ else:
+ direction = random.choice(normdir)
+ super(Fish, self).swim(worldmap, direction)
+
+ return True
+
+ # check if the fish was eaten by a shark
+ def checkeaten(self, worldmap):
+ # in this case there is 'SHARK' instead of 'FISH' at the fish's position in the map
+ return worldmap[self.x][self.y] == SHARK
+
+#------------------------------------------------------------------
+# Shark class
+#------------------------------------------------------------------
+# The shark class is part of the world
+# it defines the corpus' definitions for a shark
+class Shark(object):
+ def __init__(self, width, height, color, energy, foodenergy, breedtime):
+ self.corpus = Creature(SHARK, color, breedtime, width, height)
+ self.energy = energy
+ self.foodenergy = foodenergy
+
+ def locate(self, worldmap, pos):
+ return self.corpus.locate(worldmap, pos)
+
+ def draw(self, surface, zoom):
+ self.corpus.draw(surface, zoom)
+
+ # swim to a fish or an empty field
+ def swim(self, worldmap):
+ # make a list of fields with fish
+ fishdir = []
+ # and another with empty ones
+ normdir = []
+ for j in range(4):
+ if self.corpus.check(worldmap, j) == FISH:
+ fishdir.append(j)
+ elif self.corpus.check(worldmap, j) == EMPTY:
+ normdir.append(j)
+
+ # if there are fish around, get a random one
+ if len(fishdir) != 0:
+ direction = random.choice(fishdir)
+ elif len(normdir) == 0:
+ # there is no possible move
+ return False
+ else:
+ # otherwise just swim to an empty field
+ direction = random.choice(normdir)
+
+ if self.corpus.swim(worldmap, direction) == FISH:
+ # there was a fish, yummy
+ self.energy += self.foodenergy
+
+ return True
+
+ # higher level growing: does the shark have enough energy left?
+ def grow(self):
+ canbreed = self.corpus.grow()
+ self.energy -= 1
+ if self.energy == 0:
+ # RIP
+ return -1
+ return canbreed
+
+#-------------------------------------------
+# World class
+#-------------------------------------------
+# The world class includes all fish and sharks
+# it defines the environment
+class World(object):
+ def __init__(self, worldrect, fishcolor, sharkcolor, backgroundcolor, fishbreed, sharkbreed, sharkenergy, foodenergy, zoom):
+ self.width = worldrect[0]
+ self.height = worldrect[1]
+ self.zoom = zoom
+
+ self.fishcolor = fishcolor
+ self.sharkcolor = sharkcolor
+ self.backgroundcolor = backgroundcolor
+
+ self.fishbreed = fishbreed
+ self.sharkbreed = sharkbreed
+
+ self.sharkenergy = sharkenergy
+ self.foodenergy = foodenergy
+
+ self.fish = []
+ self.sharks = []
+
+ # get a random number of fish and sharks
+ numfish = random.randint(1, self.width * self.height / 2)
+ numsharks = random.randint(1, self.width * self.height / 2)
+
+ # create an empty map
+ self.world = clearmap(worldrect)
+
+ for j in range(numfish):
+ # bear a fish
+ newfish = Fish(race = FISH, color = self.fishcolor, breedtime = self.fishbreed, width = self.width, height = self.height)
+
+ # and locate it on the map
+ pos = (random.randint(0, self.width - 1), random.randint(0, self.height - 1))
+ if newfish.locate(self.world, pos) == True:
+ self.fish.append(newfish)
+
+ for j in range(numsharks):
+ # bear a shark
+ newshark = Shark(color = self.sharkcolor, energy = self.sharkenergy, foodenergy = self.foodenergy, breedtime = self.sharkbreed, width = self.width, height = self.height)
+
+ # locate it on the map
+ pos = (random.randint(0, self.width - 1), random.randint(0, self.height - 1))
+ if newshark.locate(self.world, pos) == True:
+ self.sharks.append(newshark)
+
+ # drawing function
+ def draw(self, surface):
+ # draw the map to the screen
+ for k in range(self.height):
+ for j in range(self.width):
+ mytype = self.world[j][k]
+
+ if mytype == EMPTY:
+ color = self.backgroundcolor
+ elif mytype == FISH:
+ color = self.fishcolor
+ else:
+ color = self.sharkcolor
+
+ pygame.draw.rect(surface, color, (j * self.zoom, k * self.zoom, self.zoom, self.zoom))
+
+ # play another round
+ def update(self):
+ # holds all new fish and sharks
+ allnewfish = []
+ allnewsharks = []
+
+ for fish in self.fish:
+ if fish.checkeaten(self.world) == True:
+ # a shark has eaten our fish
+ self.fish.remove(fish)
+ self.world[fish.x][fish.y] = EMPTY
+ else:
+ if fish.grow() == True:
+ # a new fish is born
+ newfish = Fish(race = FISH, color = self.fishcolor, breedtime = self.fishbreed, width = self.width, height = self.height)
+
+ pos = (fish.x, fish.y)
+ if fish.swim(self.world) == True:
+ # move the old fish
+
+ newfish.locate(self.world, pos)
+ allnewfish.append(newfish)
+ else:
+ # fish is not old enough -> just swim away
+ fish.swim(self.world)
+
+ # add new fish to the fishlist
+ self.fish.extend(allnewfish)
+
+ for shark in self.sharks:
+ state = shark.grow()
+ if state == -1:
+ # the shark doesn't have enough energy
+ self.sharks.remove(shark)
+ self.world[shark.corpus.x][shark.corpus.y] = EMPTY
+ elif state == True:
+ # a new shark has to be born
+ newshark = Shark(color = self.sharkcolor, energy = self.sharkenergy, foodenergy = self.foodenergy, breedtime = self.sharkbreed, width = self.width, height = self.height)
+
+ pos = (shark.corpus.x, shark.corpus.y)
+ if shark.swim(self.world) == True:
+ # swim away, old fish
+ newshark.locate(self.world, pos)
+ allnewsharks.append(newshark)
+ else:
+ # nothing happend, just move
+ shark.swim(self.world)
+
+ # add new sharks
+ self.sharks.extend(allnewsharks)
+
+def parse_arguments():
+ # Parse arguments
+ parser = argparse.ArgumentParser(description = "Wa-Tor Implementation")
+ parser.add_argument('-w', '--width', help = "Width of the world", default = 100, type = int)
+ parser.add_argument('-v', '--height', help = "Height of the world", default = 50, type = int)
+ parser.add_argument('-f', '--fishcolor', help = "Color of the fish", default = 'blue', type = str)
+ parser.add_argument('-s', '--sharkcolor', help = "Color of the shark", default = 'green', type = str)
+ parser.add_argument('-a', '--backgroundcolor', help = "Background color", default = 'black', type = str)
+ parser.add_argument('-b', '--fishbreed', help = "Number of rounds that the fish need to breed", default = 4, type = int)
+ parser.add_argument('-c', '--sharkbreed', help = "Number of rounds that the sharks need to breed", default = 5, type = int)
+ parser.add_argument('-e', '--sharkenergy', help = "Number of energy points the sharks get at the beginning", default = 3, type = int)
+ parser.add_argument('-g', '--foodenergy', help = "Number of energy points a shark earns when it eats a fish", default = 1, type = int)
+ parser.add_argument('-z', '--zoom', help = "Zoomimg factor", default = 10, type = int)
+ args = parser.parse_args()
+ return args
+
+def game_loop(args):
+ # Check arguments
+ if args.zoom < 1 or args.zoom > 100:
+ print("Error: --zoom invalid")
+ exit(0)
+ if args.width < 0 or args.width > 1000 or args.height < 0 or args.height > 1000:
+ print("Error: --world invalid")
+ exit(0)
+ if args.fishbreed < 1 or args.fishbreed > 1000:
+ print("Errof: --fishbreed invalid")
+ exit(0)
+ if args.sharkbreed < 1 or args.sharkbreed > 1000:
+ print("Error: --sharkbreed invalid")
+ exit(0)
+ if args.sharkenergy < 1 or args.sharkenergy > 1000:
+ print("Error: --sharkenergy invalid")
+ exit(0)
+ if args.foodenergy < 0 or args.foodenergy > 1000:
+ print("Error: --foodenergy invalid")
+ exit(0)
+
+ # init the world
+ world = World((args.width, args.height), fishcolor = Color(args.fishcolor), sharkcolor = Color(args.sharkcolor), backgroundcolor = Color(args.backgroundcolor), fishbreed = args.fishbreed, sharkbreed = args.sharkbreed, sharkenergy = args.sharkenergy, foodenergy = args.foodenergy, zoom = args.zoom)
+
+ # init the window
+ windowsize = (args.width * args.zoom, args.height * args.zoom)
+ display = pygame.display.set_mode(windowsize)
+ pygame.display.set_caption("Wa-Tor")
+
+ loop = True
+ # main loop
+ while loop == True:
+ world.update()
+ world.draw(display)
+ pygame.display.update()
+
+ for event in pygame.event.get():
+ if event.type == QUIT:
+ loop = False
+
+if __name__ == '__main__':
+ game_loop(parse_arguments())