Python
Nothing fancy. I kept on adding stuff, so refactoring might be in order. (And I didn't do unitest so bugs might still be present).
I gave random names to lumberjacks and bears.Trees are i
, then I
, then #
,Lumberjacks are x
,Bears are o
import osfrom random import randint, choice, shufflefrom time import sleepNGRID = 15SLEEPTIME = 0.0125DURATION = 4800VERBOSE = True###initgrid = [[[] for _ in range(NGRID)] for _ in range(NGRID)]#Money earned this yearn_lumbers = 0#Lumberjacks killed this yearn_maul = 0tick = 0events = []#total number ofd_total = {'trees':0,'lumberjacks': 0,'bears': 0,'cut': 0,'maul': 0,'capture': 0,'lumbers': 0,'fired': 0}d_oldest = {'tree': 0,'lumberjack': (0, ""),'bear': (0, "")}d_most = {'n_maul': (0, ""),'n_lumber': (0, ""),'n_cut': (0, "")}d_year = {'n_maul': 0,'n_lumber': 0}###Classesclass Tree(object):"""Represent a Sapling, Tree, or Elder Tree""" def __init__(self, coords, m=0, t='Sapling'): self.months = m self.typeof = t self.coords = coords def grow(self, m=1):"""the tree grows 1 month and its type might change""" self.months = self.months + m if self.months == 12: self.typeof = 'Tree' elif self.months == 480: self.typeof = 'Elder Tree' def __str__(self): if self.typeof == 'Sapling': return 'i' elif self.typeof == 'Tree': return 'I' else: return '#'class Animated(object):"""Animated beings can move""" def __init__(self, coords): self.coords = coords self.old_coords = None self.months = 0 def where(self): return c_neighbors(self.coords) def choose_new_coords(self): self.old_coords = self.coords possible = self.where() if possible: direction = choice(self.where()) self.coords = [(self.coords[i]+direction[i]) % NGRID for i in range(2)]# def __del__(self):# print "died at "+ str(self.coords)class Lumberjack(Animated):"""Lumberjacks chop down trees""" def __init__(self, coords): super(Lumberjack, self).__init__(coords) self.nb_cut = 0 self.nb_lumber = 0 self.name = gen_name("l") def __str__(self): return "x"class Bear(Animated):"""Bears maul""" def __init__(self, coords): super(Bear, self).__init__(coords) self.nb_maul = 0 self.name = gen_name("b") def where(self): return c_land_neighbors(self.coords) def __str__(self): return "o"###list of coordsdef c_neighbors(coords):"""returns the list of coordinates of adjacent cells""" return [[(coords[0] + i) % NGRID, (coords[1] + j) % NGRID] \ for i in [-1, 0, 1] \ for j in [-1, 0, 1] \ if (i,j) != (0, 0)]def c_empty_neighbors(coords):"""returns the list of coordinates of adjacent cells that are empty """ return [[i, j] for [i,j] in c_neighbors(coords) if grid[i][j] == []]def c_land_neighbors(coords):"""returns the list of coordinates of adjacent cells that contain not Trees for bears""" return [[i, j] for [i,j] in c_neighbors(coords)\ if (grid[i][j] == []) or (not isinstance(grid[i][j][0], Tree))]def c_empty_cells():"""returns list of coords of empty cells in the grid""" return [[i, j] for i in range(NGRID) for j in range(NGRID) if grid[i][j] == []]def c_not_bear_cells():"""returns list of coords of cells without bear""" return [[i, j] for i in range(NGRID) for j in range(NGRID) \ if not isinstance(grid[i][j], Bear)]###one lessdef maul(lumberjack):"""a lumberjack will die""" global n_maul n_maul = n_maul + 1 d_total['maul'] = d_total['maul'] + 1 remove_from_grid(lumberjack.coords, lumberjack) return lumberjack.name +" is sent to hospital" + check_lumberjacks()def capture_bear():"""too many mauls, a Zoo traps a bear""" d_total['capture'] = d_total['capture'] + 1 bear = choice(get_bears()) remove_from_grid(bear.coords, bear) return bear.name +" has been captured"def fire_lumberjack():"""the job is not done correctly, one lumberjack is let go""" d_total['fired'] = d_total['fired'] + 1 lumberjack = choice(get_lumberjacks()) remove_from_grid(lumberjack.coords, lumberjack) return lumberjack.name +" has been fired" + check_lumberjacks()def remove_from_grid(coords, item):"""remove item from the grid at the coords""" grid[coords[0]][coords[1]].remove(item) del item###one moredef new_animate(class_):"""a new lumberjack or bear joins the forest""" if class_==Bear: d_total['bears'] = d_total['bears'] + 1 x, y = choice(c_empty_cells()) else: d_total['lumberjacks'] = d_total['lumberjacks'] + 1 x, y = choice(c_not_bear_cells()) new_being = class_([x,y]) grid[x][y].append(new_being) return "a new " + class_.__name__ +" enters the forest: " + new_being.namedef check_lumberjacks():"""we will never reduce our Lumberjack labor force below 0""" if len(get_lumberjacks())==0: return " - no more lumberjack, " + new_animate(Lumberjack) return ""###movementsdef move_on_grid(being): [x, y] = being.old_coords grid[x][y].remove(being) [x, y] = being.coords grid[x][y].append(being)def move_lumberjack(lumberjack):"""Lumberjacks move 3 times if they don't encounter a (Elder) Tree or a Bear""" global n_lumbers for _ in range(3): lumberjack.choose_new_coords() move_on_grid(lumberjack) [x, y] = lumberjack.coords #is there something at the new coordinate? #move append so this lumberjack is at the end if grid[x][y][:-1] != []: if isinstance(grid[x][y][0], Tree): the_tree = grid[x][y][0] price = worth(the_tree) if price > 0: lumberjack.nb_cut = lumberjack.nb_cut + 1 d_most['n_cut'] = max((lumberjack.nb_cut, lumberjack.name), \ d_most['n_cut']) d_total['cut'] = d_total['cut'] + 1 n_lumbers = n_lumbers + price d_total['lumbers'] = d_total['lumbers'] + 1 lumberjack.nb_lumber = lumberjack.nb_lumber + price d_most['n_lumber'] = max(d_most['n_lumber'], \ (lumberjack.nb_lumber, lumberjack.name)) remove_from_grid([x, y], the_tree) return lumberjack.name +" cuts 1 " + the_tree.typeof #if there is a bear, all lumberjacks have been sent to hospital if isinstance(grid[x][y][0], Bear): #the first bear is the killer b = grid[x][y][0] b.nb_maul = b.nb_maul + 1 d_most['n_maul'] = max((b.nb_maul, b.name), d_most['n_maul']) return maul(lumberjack) return Nonedef move_bear(bear):"""Bears move 5 times if they don't encounter a Lumberjack""" for _ in range(5): bear.choose_new_coords() move_on_grid(bear) [x, y] = bear.coords there_was_something = (grid[x][y][:-1] != []) if there_was_something: #bears wander where there is no tree #so it's either a lumberjack or another bear #can't be both. if isinstance(grid[x][y][0], Lumberjack): bear.nb_maul = bear.nb_maul + 1 d_most['n_maul'] = max((bear.nb_maul, bear.name), \ d_most['n_maul']) return maul(grid[x][y][0]) return None###get objectsdef get_objects(class_):"""get a list of instances in the grid""" l = [] for i in range(NGRID): for j in range(NGRID): if grid[i][j]: for k in grid[i][j]: if isinstance(k, class_): l.append(k) return ldef get_trees():"""list of trees""" return get_objects(Tree)def get_bears():"""list of bears""" return get_objects(Bear)def get_lumberjacks():"""list of lumberjacks""" return get_objects(Lumberjack)###utilsdef gen_name(which="l"):"""generate random name""" name = "" for _ in range(randint(1,4)): name = name + choice("bcdfghjklmnprstvwxz") + choice("auiey") if which == "b": name = name[::-1] return name.capitalize()def worth(tree):"""pieces for a tree""" if tree.typeof == 'Elder Tree': return 2 if tree.typeof == 'Tree': return 1 return 0def one_month():"""a step of one month""" events = [] global tick tick = tick + 1 #each Tree can spawn a new sapling for t in get_trees(): l_empty_spaces = c_empty_neighbors(t.coords) percent = 10 if t.typeof == 'Tree' else \ 20 if t.typeof == 'Elder Tree' else 0 if (randint(1,100) < percent): if l_empty_spaces: [x, y] = choice(l_empty_spaces) grid[x][y] = [Tree([x,y])] d_total['trees'] = d_total['trees'] + 1 t.grow() d_oldest['tree'] = max(t.months, d_oldest['tree']) #each lumberjack/bear moves for l in get_lumberjacks(): l.months = l.months + 1 d_oldest['lumberjack'] = max((l.months, l.name), \ d_oldest['lumberjack']) event = move_lumberjack(l) if event: events.append(event) for b in get_bears(): b.months = b.months + 1 d_oldest['bear'] = max((b.months, b.name), d_oldest['bear']) event = move_bear(b) if event: events.append(event) return eventsdef print_grid():"""print the grid if more than 1 thing is at a place, print the last. At 1 place, there is - at most a tree and possibly several lumberjack - or 1 bear""" print "-" * 2 * NGRID print '\n'.join([''.join([str(i[-1]) if i != [] else '' \ for i in line]) \ for line in grid]) print "-" * 2 * NGRIDdef clean():"""clear the console""" os.system('cls' if os.name == 'nt' else 'clear')def print_grid_and_events():"""print grid and list of events""" clean() print_grid() if VERBOSE: print '\n'.join(events) print "-" * 2 * NGRID###populate the forestl = c_empty_cells()shuffle(l)for x, y in l[:((NGRID*NGRID) / 2)]: grid[x][y] = [Tree([x, y], 12, 'Tree')] d_total['trees'] = d_total['trees'] + 1l = c_empty_cells()shuffle(l)for x, y in l[:((NGRID*NGRID) / 10)]: grid[x][y] = [Lumberjack([x, y])] d_total['lumberjacks'] = d_total['lumberjacks'] + 1l = c_empty_cells()shuffle(l)for x, y in l[:((NGRID*NGRID) / 10)]: grid[x][y] = [Bear([x, y])] d_total['bears'] = d_total['bears'] + 1###time goes onwhile (tick <= DURATION and len(get_trees())>0): events = one_month() #end of the year if (tick % 12)==0: events.append("End of the year") #lumber tracking nlumberjacks = len(get_lumberjacks()) events.append(str(n_lumbers) +" lumbers VS " +\ str(nlumberjacks) +" Lumberjacks") if n_lumbers >= nlumberjacks: n_hire = n_lumbers/nlumberjacks events.append("we hire " + str(n_hire) +\" new Lumberjack" + ("s" if (n_hire > 1) else "")) for _ in range(n_hire): events.append(new_animate(Lumberjack)) else: events.append(fire_lumberjack()) d_year['n_lumber'] = max(d_year['n_lumber'], n_lumbers) n_lumbers = 0 #maul tracking events.append("maul this year: " + str(n_maul)) if n_maul == 0: events.append(new_animate(Bear)) else: events.append(capture_bear()) d_year['n_maul'] = max(d_year['n_maul'], n_maul) n_maul = 0 print_grid_and_events() sleep(SLEEPTIME)print "-"*70print "End of the game"print "-"*70print "month:" + str(tick - 1)print "number of trees still alive: " + str(len(get_trees()))print "number of lumberjacks still alive: " + str(len(get_lumberjacks()))print "number of bears still alive: " + str(len(get_bears()))print "-"*70print "oldest Tree ever is/was: " + str(d_oldest['tree'])print "oldest Lumberjack ever is/was: " + str(d_oldest['lumberjack'][0]) + \" yo " + d_oldest['lumberjack'][1]print "oldest Bear ever is/was: " + str(d_oldest['bear'][0]) + \" yo " + d_oldest['bear'][1]print "-"*70print "max cut by a Lumberjack: " + str(d_most['n_cut'][0]) + \" by " + str(d_most['n_cut'][1])print "max lumber by a Lumberjack: " + str(d_most['n_lumber'][0]) + \" by " + str(d_most['n_lumber'][1])print "max maul by a Bear: " + str(d_most['n_maul'][0]) + \" by " + str(d_most['n_maul'][1])print "-"*70print "max lumber in a year: " + str(d_year['n_lumber'])print "max maul in a year: " + str(d_year['n_maul'])print "-"*70print "Total of:"for i, j in d_total.items(): print i, str(j)
Some outputs:
------------------------------ x I I x i I i i i i I I x ii I I i I I i i o i i I I I i i I x i I I I I I I i x------------------------------Dy is sent to hospitalLehuniru cuts 1 Tree------------------------------
End of the year
------------------------------ x xi I I i I x I i i x I I i I i I i i I i I i x i I i I o x------------------------------Fuha cuts 1 TreeKa cuts 1 TreeKy is sent to hospitalEnd of the year11 lumbers VS 4 Lumberjackswe hire 2 new Lumberjacksa new Lumberjack enters the forest: Dia new Lumberjack enters the forest: Dymaul this year: 6Evykut has been captured------------------------------
End of the game
------------------------------ x i x x x x x i x i I I i x x I i x x i i x i i i i I i i I I i I iI i i i i x i I i I I I x i I I x------------------------------Vanabixy cuts 1 TreeFasiguvy cuts 1 Tree----------------------------------------------------------------------------------------------------End of the game----------------------------------------------------------------------month:4800number of trees still alive: 36number of lumberjacks still alive: 15number of bears still alive: 0----------------------------------------------------------------------oldest Tree ever is/was: 129oldest Lumberjack ever is/was: 308 yo Cejukaoldest Bear ever is/was: 288 yo Ekyx----------------------------------------------------------------------max cut by a Lumberjack: 44 by Cejukamax lumber by a Lumberjack: 44 by Cejukamax maul by a Bear: 52 by Ekyx----------------------------------------------------------------------max lumber in a year: 84max maul in a year: 86----------------------------------------------------------------------Total of:bears 211cut 5054fired 67capture 211lumberjacks 1177lumbers 5054maul 1095trees 5090