The Forest Game (KotH, WIP)
Summary
You have been given a space of land to plant trees in. Unfortunately, due to an administrative mix-up, so have 4 other people. You are in a competition with them to make the most money out of your trees within the next 100 years.
The map
A 10 by 10 grid, representing the area of land. Each square will be one of the following:
- A number,
0 to 4, representing a player ., representing a seed (more later) i, representing a sapling T, representing a tree F, an ongoing fire , an empty space
Actions
Actions, given by your program, are 1 or 2 characters long. The first is the type:
. - plant a seed, costs 1 i - plant a sapling, costs 10 F - start a fire, costs 5 m - move, costs 0 w - work, gains 1 (what you do for easy points/to do nothing) - - harvest, variable gains (see below)
Anything else as the first character will result in ignored command. The second character is one of `^'<>,v., a direction, which refers to the relative location of the square on which to perform the command:
` ^ ' NW N NE < > --> W E , v . SW S SE
For the work command, the second character need not be present, but must be one of the eight if it is. An invalid command is ignored.
Growing
Seeds become saplings, saplings trees. After 5 rounds (25 turns), a seed becomes a sapling with the probability \$\frac{8 - C}8\$ where \$C\$ is the number of nearby (diagonally or orthogonally adjacent) saplings or trees. Saplings become trees after 7 rounds, with the same probability (\$C\$ here is only trees). This is worked out from the top left, going across each row in turn, meaning that each seed/sapling growth may be affected by saplings/trees created that turn.
Value
When harvested, saplings/trees add to your score. Saplings are valued at 15, trees at 20. After every round, a tree gains 1 point of value, up to a maximum of 40 points. Seeds cannot be harvested, nor can other players' saplings/trees.
Fires
Fires spread from the point you set them to all nearby trees and saplings, unless there is a player other than you also nearby. Example:
T T T T i5 i5 F5 5 TTTTTT --> FFTTTT --> FTTT --> TTT F1 ii 1 ii 1 ii 1 ii i i i i
Where 1 is you and 5 is the other player. Each step represents one turn (not one round).
Tournament
Each game, you start with 15 points, and loose/gain them as described in the 'actions' and 'value' sections. The aim is to be the player with the most points at the end of 100 rounds (500 turns in total). Each game will be played 6 times, and then repeated until one player has won more than any of the others. This collection of 6+ games is a 'match'. Every two days, if there have been new players added, the players will be split up into groups of 5, padded out with simple bots of mine if necessary. The winners of each of these will be split into groups of five and the above process repeated until there is only one group of five, the winner of which is the victor!
I/O
Your submission should be a Python 3 program, with a method run defined in the global scope. This method will be called with the following parameters:
map_ - a list of ten lists of single character strings. This will be a deep copy of the map, each string is one of 01234.iTF, representing that square. round_ - the round number points - a list of integers, representing the number of points each player has, in order. num - whereabouts on the points list you come, also the number representing you and where you come in the turn order.
It should output the two/one character string mentioned above.
Controller
WIP, extremely buggy
''' Rules --- map, 20 by 20 squares, starts empty with randomly placed players square can be: ' ' - empty '1' - [0-4], player '.' - seed 'i' - sapling 'T' - tree 'F' - flames actions: 'm' - move 'i' - plant sapling '.' - plant seed '-' - harvest tree 'F' - start fire 'w' - work (dir optional and ignored) '?' - other, nothing each action other than move should be accompanied by a direction, [<>^v`,'.O] = (W,E,N,S,NW,SW,NE,SE,O) flames: - go out if person nearby other than starter - turn every nearby tree/sapling to flames, 33% each - go out, leave ' ' costs/bonuses: 'm' - none 'i' - -10 '.' - -1 '-' - +15 for sapling, +20 for tree + turns living max. +40 'F' - -1 'w' - +1 '?' - none growing: . > l - (8-nearby [lT])/8 chance, after 5 turns l > T - (8-nearby [T])/8 chance, after 7 turns T+ - +1 value every turn, max. 40 every five turns, tree drops a seed in an empty nearby square start at 10 points game end after 100 rounds I/O --- ''' import random, os, time, sys class Item(object): def __init__(self, x, y, game, creator=None): self.x = x self.y = y self.game = game self.creator = creator class Flame(Item): def update(self, around): burn = [] for i in around: if str(i) in map(str, range(6)): if str(i) != str(self.creator): return elif str(i) in 'Ti': burn.append(i) for i in burn: self.game.place(Flame, i.x, i.y, self.creator) self.game.place(Empty, self.x, self.y) def __str__(self): return 'F' class Seed(Item): def __init__(self, x, y, game, creator, count=25, _next=None): _next = _next or Sapling super(Seed, self).__init__(x, y, game, creator) self.counter = count self.creator = creator self.next = _next def update(self, around): self.counter -= 1 if self.counter: return pos = sum(str(x) in 'Ti' for x in around) if random.randrange(8) in range(pos): self.game.place(Empty, self.x, self.y) return self.game.place(self.next, self.x, self.y, self.creator) def __str__(self): return '.' class Sapling(Seed): def __init__(self, x, y, game, creator): super(Sapling, self).__init__(x, y, game, creator, 35, Tree) def __str__(self): return 'i' def __int__(self): return 15 class Tree(Item): def __init__(self, x, y, game, creator): super(Tree, self).__init__(x, y, game, creator) self.val = 20 def update(self, around): self.val += 1 if self.val > 40: self.val = 40 def __str__(self): return 'T' def __int__(self): return self.val class Empty(Item): def update(self, around): pass def __str__(self): return ' ' class Player(object): def __init__(self, x, y, name, game): self.game = game self.x = x self.y = y self.name = name self.around = (None,) * 8 self.points = 15 def update(self, around): self.around = around def command(self, text): text = "mv" if len(text) != 2: if len(text) != 1: return else: self.points += text[0] == 'w' return dirs = "`^'<p>,v." #p = placeholder if text[1] not in dirs: return ny = self.y + (dirs.index(text[1]) % 3) - 1 nx = self.x + int(dirs.index(text[1]) / 3) - 1 if (nx, ny) == (self.x, self.y): return itm = self.around["`<,^v'>.".index(text[1])] if text[0] == 'w': self.points += 1 elif ny < 0 or nx < 0 or not itm: #remove for wrapping return if text[0] == 'm': if str(itm) == ' ': self.game.move(self.x, self.y, nx, ny) elif text[0] == 'F' and self.points > 0: if str(itm) in 'Ti': #never!!! self.game.place(Flame, nx, ny, self) self.points -= 1 elif text[0] == '.' and self.points > 0: if str(itm) == ' ': print('.') self.game.place(Seed, nx, ny, self) self.points -= 1 elif text[0] == 'l' and self.points > 9: if str(itm) == ' ': print('l') self.game.place(Sapling, nx, ny, self) self.points -= 1 elif text[0] == '-': if str(itm) in 'Ti': if itm.creator == str(self): #never!! self.game.place(Empty, nx, ny) self.points += int(itm) def __str__(self): return str(self.name) class Game(object): def __init__(self, players, names, size=20): self.map = [] choose = [] self.names = names for x in range(size): self.map.append([]) for y in range(size): self.map[-1].append(Empty(x, y, self)) choose.append((x, y)) self.players = {} random.shuffle(choose) for i in range(len(players)): pos = choose.pop() p = Player(*pos, str(i), self) self.players[players[i]] = p self.map[pos[0]][pos[1]] = p self.round(1) def round(self, number): for i in self.players: self.updatemap() self.turn(i, number) if not 'idlelib.run' in sys.modules: time.sleep(0.04) os.system('cls') print(' |0 1 2 3 4 5 6 7 8 9') print('---------------------') [print(str(self.map.index(i)) + '|' + ' '.join(str(j) for j in i)) for i in self.map] if number != 100: self.round(number+1) else: [print(' '.join(str(j) for j in i)) for i in self.map] for i in self.players: print(names[i], self.players[i].points, sep=': ') def turn(self, player, rn): points = [] n = 0 for i in self.players: if i == player: num = n points.append(self.players[i].points) text = player(map_=[x[:] for x in self.map], num=num, points=points, round_=rn) self.players[player].command(text) def place(self, item_t, x, y, creator=None): try: itm = item_t(x, y, self, creator) self.map[x][y] = itm return itm except IndexError: pass def move(self, ox, oy, x, y): try: self.map[x][y] itm = self.map[ox][oy] self.place(Empty, ox, oy) self.map[x][y] = itm itm.x = x itm.y = y except IndexError: pass def updatemap(self): for x in range(len(self.map)): for y in range(len(self.map[x])): around = [] for rx in (-1, 0, 1): for ry in (-1, 0, 1): if rx or ry: try: around.append(self.map[x+rx][y+ry]) except IndexError: around.append('') if str(self.map[x][y]).strip(): print(' '.join(str(i) for i in around[:3]), ' '.join(str(i) for i in around[3:6]), ' '.join(str(i) for i in around[6:]), str(self.map[x][y]), sep='\n', end='-----') self.map[x][y].update(around) import burnitall, flamingworker, hardworker, plantandwait, seedandreap allnames = ('Burn It All', 'Flaming Worker', 'Hard-worker', 'Plant And Wait', 'Seed And Reap') allplayers = (burnitall, flamingworker, hardworker, plantandwait, seedandreap) players = [] names = {} for i in allplayers: players.append(i.run) names[i.run] = allnames[allplayers.index(i)] Game(players, names, 10) input()
Game results
Nothing yet!
king-of-the-hillai-playergamepython
Sandbox
- Any thoughts? Do you like it?
- All numbers, rules are undecided, tell me what you think I should change.
- I know the controller has many bugs, I posted it here to show that one is being made but it's very much not ready to use.
- That doesn't mean I don't want bug reports, if you use it and spot one, please tell me.
- If you don't like Python - tough. It's all I've got on my computer*1, and I don't have space for much else.
*1 I tell a lie, I have got Java, but so much fuss in implementing it for one more language? I'll think about it...