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...