Be the Richest Mammut!
The Game
This game is an adaptation of a board game called Mammut, and basically an optimization problem.
Each match contains five players and five rounds, in which every player participates. Every round starts with a bunch of tiles being flipped at random on one of their sides, and put in the middle stack
The tile composition will be fixed, but has not been completely decided yet There will be 30-35 of them, and each of them will have two different sides, with exactly 15 different types of tiles, and about half of those only having one single instance available.
A random player is chosen as the starting player for the first round, and performance will decide the starter for the following four rounds.
In order, each player that doesn't own any tiles will take an action, and this will keep going on until every player has at least one tile.
The actions available are:
- Take an arbitrary number of tiles from the middle stack.
- Take all of the tiles owned by another player, and put one of them back in the middle stack.
Obviously, you can take the entire middle stack, but if there is at least one other player without tiles and you take too many, he will most likely steal your tiles right after.
Scoring
Every player starts with 10 points, and if they end a scoring phase under zero, they will be given enough free points to go back to zero.
When everyone has tiles, the round is over, and we move on to scoring that round. Since this is played by bots and not humans, an infinite loop is possible, so after 1000 actions, the round will be stopped by force, and the players participating in the infinite loop who ended up empty ended will naturally end this round with a terrible score.
Scoring happens all at once, and you get (or lose) points according to the tiles you have, and the tiles the other players have. When scoring is done, we move on to the next round, or declare the winner if that was the fifth round.
The Tiles
There are different types of tiles, and you job is basically to find the best balance between them while not having enough to make your stack worth stealing.
- Fire | The player who has the fewest fire tiles loses 5 points
- Meat | The three players owning the most meat tiles get 8, 5 and 2 points respectively
- Fur | Every fur tile gives you onw "fur point". During every round after the first, the player with the most fur points plays first. At the end of each round, the player with the most fur tiles gets the round number in points (1-5), while the one who has the least loses the round number in points.
- Ivory Tile | Every Ivory tile gives you two points.
- Axe Tile | (This one should be discussed) Every axe tile gives you one point, and every axe Tile obtained in the last round is Worth 3 points
- Animal Tiles | There are 7 different animals (Bat, Opossum, Bunny, Buffalo, Squirrel, Beaver and Duck), and only one of each in the game. When you end the round with one, you "obtain" this animal, and getting the same one again will do nothing. At the end of the game, depending on the number of animals you have obtained, you get points. (0: 0, 1:0, 2:0, 3:4, 4:9, 5:15, 6:22, 7:30)
- Mystery Tile | If you get a mystery tile, it will be turned around to reveal its other side during the scoring phase. The other side can't be another mystery tile or an animal tile.
- Tie-Breaker Tile | This tile serves as a tie breaker. One side is the "clockwise" side, and the other side is the "counter-clockwise", so every round will contain a tie-breaker tile. During any and all ties during scoring, the tie-breaker tile decides who wins or loses.
Clockwise?
At the start of the game, every player will be given a random ID between 1 and 5. The player with ID 1 will start the game. Then, for the following rounds, the most fur points decides who starts, and the ID decides the order. Example: ID 3 has the most furs, then the order will be [3, 4, 5, 1, 2].
This is considered "clockwise". The counter-clockwise order would be [3, 2, 1, 5, 4]. This is important, because when dealing with ties, the tie-breaker tile takes the order into account.
If player 4 owns the clockwise tie-breaker tiles, and has 3 meats. Player 1 and 2 also have three meats. The first, second and third place in meat then go to players ID 4, 1 and 2 respectively. If everyone has 3 fires, except player 3 and 5 who have 1, then player 3 is the one to lose points. Having the tie-breaker tiles means you are first in the tie-breaking order, and that tile's visible side decide the rest of the order.
Challenge specifications
You must make a C# class that inherits from a "Player" class. You must also override the method
List<int> ChooseTiles(Dictionary<int, List<Tile>> otherPlayers, List<Tile> center)
This method takes a dictionary of player IDs and List of tiles (could be empty), that are each player's tiles at the moment, plus a list of tiles in the middle. You must return a list of integer, which are the IDs of the tiles you want. If you try to get tiles illegally (not following the instructions for taking an action, which are either any number of tiles from the middle or all tiles except one from a player), you will be asked to choose one more time, and if you fail to follow the rules, you will be counted as "attempting to cheat" and removed from the "playing" pool during this round, so you will get scored for an empty hand. The same thing goes for throwing exceptions and infinite loops (Execution lasting more than 5 seconds). You are given one more chance then given an empty hadn for that round.
Here is the class Player you will be inheriting from:
public class Player
{
public int ID;
public int currentPoints;
public int currentFurs;
public List<Tile> currentTiles;
public List<TileType> animalsGotten;
public Player(int id)
{
ID = id;
currentPoints = 10;
currentFurs = 0;
currentTiles = new List<Tile>();
animauxGotten = new List<TileType>();
}
public virtual List<int> ChooseTiles(Dictionary<int, List<Tile>> otherPlayers, List<Tile> center)
{
throw new Exception("Fake players don't get to play!");
}
public virtual string GetName()
{
return "Player";
}
}
You should also override the GetName() function, but it is not required.
You are allowed to create as many private functions or attributes as you want to store data during a game, but each match will create a new instance of your player.
The Tournament
tournament will be played in a round-robin fashion. You are not garanteed a match with every single combination of four opponents available, but you are garanteed at least one match in common with every other bot, and everyone will play the same number of matches. You will also not play twice with the same 5 players. The total number of matches will depend on the number of participants.
For each match, the first player will get 5 points, and the others will get respectively 3, 2, 1 and zero points depending on their points earned during the match. Furthermore, and ties in points will not be resolved, and the points of the occupied positions split between tied players. This means that if the points are (40, 37, 37, 37, 35), the points are (5, 2, 2, 2, 0)