Camel Up Cup: An AI board game tournament

11

6

Camel Up Cup 2k18

In this challenge, we will be playing the semi-popular board game Camel Up.

Camel Up! is a board game that has players betting on camels to win rounds, win the game or lose the game, set traps to influence movement or move a camel. Each of these decisions rewards you with the chance of getting some money, which is what determines the winner. Players should use probability, game-state considerations and opponent tenancy to make their decisions. Here is a short video showing players how to play.

How to play

Here is a rough idea of how to play. Watching one of the videos may be more helpful because they have visuals :)

On your turn you have 4 options.

  1. Move a camel. This picks a camel from those who haven't moved and moves it between 1-3 spaces. You get 1 coin. Rounds end when all five camels have moved, they can then all move
  2. Place a trap. This goes on the board until the end of round. You choose +1/-1 trap. If a camel or camel stack lands on it they move +1/-1 and you get a coin. You cannot place a trap on square 0. You can place a trap where camels are, although it will only affect camels that land on it after.
  3. Round winner bet. You take a bet on a round winner. They win you get 5/3/2/1 depending on if you were the 1st/2nd/3rd to bet on that camel.
  4. Game winner/loser. You take a bet on who will be in first or last at the end of the game. you get 8/5/3/1/1 (I think) based on if you were 1st/2nd/3rd/etc to bet on that camel

Notes:

  • There are 5 camels. They start on a position randomly from 0-2.
  • When a camel is moved (see above for what triggers this) they move 1-3 squares. If they would be placed on a square with another camel they are put "on top" of the other, creating a camel stack. If a camel is to move it moves all camels above it on the camel stack. The camel at the top of the stack is considered in the lead
  • If you land on a +1 trap (see above for what triggers this) you move one square further forward. Standard stacking rules apply.
  • However if you hit a -1 trap you move one square backwards. You go under the stack of camels that are on that square, if any.
  • The game ends when a camel hits square 16. This immediately invokes round end and game end triggers
  • Game winner/loser bets can be done only once per camel. I.e. you cannot bet on a camel to win and lose the game

Challenge

In this challenge, you will write a Python 3 program to play a four player, winner takes all glory game of Camel Up

Your program will receive the gamestate, which contains:

  • camel_track: with the locations of the camels
  • trap_track: with the location of the traps (entry of the form [trap_type (-1,1), player])
  • player_has_placed_trap: an array telling you if players have placed a trap this round
  • round_bets: an array of the bets placed this round. Of the form [camel,player]
  • game_winner_bets / game_loser_bets: arrays of the bets players made for camels to win or lose the game. You will only be able to see the value of players who made the bets, not who they bet on. You can know who you bet on. #of the form [camel,player]
  • player_game_bets: another representation of the game_winner_bets / game_loser_bets. Again, only look at the bets that your bot made.
  • player_money_values: an array showing the amount of money each player has.
  • camel_yet_to_move: An array showing if a camel has moved this round.

On top of the gamestate you also get:

  • player: an integer telling you what player number you are (0-3).

Syntax for what players should return is:

  • [0] : Move Camel
  • [1,trap_type,trap_location] : Place Trap
  • [2,projected_round_winner] : Make Round Winner Bet
  • [3,projected_game_winner] : Make Game Winner Bet
  • [4,projected_game_loser] : Make Game Loser Bet

This should be wrapped in a move(player,gamestate) method

For instance, here's a player that will make a round winner bet if they are in last place. If they aren't then they will place a trap on a random square.

class Player1(PlayerInterface):
     def move(player,g):
         if min(g.player_money_values) == g.player_money_values[player]:
            return [2,random.randint(0,len(g.camels)-1)]
        return [1,math.floor(2*random.random())*2-1,random.randint(1,10)]

The game was chosen for several reasons: it has a relatively small pool of options to select from (roughly 20 choices per turn, easily narrowed down to usually about 3-4), games are short and there is an element of luck (makes it so even the "bad" bots can win).

Gameplay

The tournament runner can be found here: camel-up-cup. Run camelup.py to run a tournament or the function PlayGame to run games. I'll keep that repository updated with new submissions. Example programs can be found in players.py.

A tournament consists of 100 games per 10 players (rounded up, so 14 players means 200 games). Each game will be four random players selected from the pool of players to fill the four positions. Players will not be able to be in the game twice.

Scoring

The winner of each game is the player with the most money at the end of the game. In the case of a tie at the end of a game all players with the maximum money amount are awarded a point. The player with the most points at the end of the tournament wins. I will post scores as I run the games.

The players submitted will be added to the pool. I added three really dumb bots and one that I made to start.

Caveats

Do not modify the inputs. Do not attempt to affect the execution of any other program, except via cooperating or defecting. Do not make a sacrificial submission that attempts to recognize another submission and benefit that opponent at its own expense. Standard loopholes are banned.

Limit the time taken by your bot to be ~10s per turn.

Submissions may not duplicate earlier submissions.

Please don't view game_winner or game_loser bets from other players. Its pretty easy to do but still cheating.

If you have any questions, feel free to ask.

Winning

The competition will stay open indefinitely, as new submissions are posted. However, I will declare a winner (accept an answer) based on the results one month after this question was posted (July 20th).

Results

Player0: 12
Player1: 0
Player2: 1
Sir_Humpfree_Bogart: 87

Tyler Barron

Posted 2018-06-20T04:27:12.827

Reputation: 181

Maybe I read past it, but how many Camels are there in play? Also, how many squares do they have to travel to get to the other side? Based on your GitHub code I'm pretty sure it's 5 camels and 25 squares, but I didn't see this mentioned in the challenge description. As for placing bets, can we bet any amount, or it will bet 1 by default? Do we have a spending limit, or can we bet every round indefinitely? As for players moving a camel, which camel is moved? The camel with your matching player-nr? If yes, why are there 4 players but 5 camels? – Kevin Cruijssen – 2018-06-20T07:02:07.417

1Would have been perfect to have Perl answers – The random guy – 2018-06-20T07:05:25.173

Welcome to PPCG! – AdmBorkBork – 2018-06-20T12:29:18.887

100 games per 10 players seems pretty low IMO, especially with a game with so much randomness – Nathan Merrill – 2018-06-20T12:49:56.657

To make it clear to future readers: second place is worth as much as last place, so bet it all for the win. – Nathan Merrill – 2018-06-20T12:50:23.527

" I added three really dumb bots and one that I made to start.": You should post them below if they are going to compete – Nathan Merrill – 2018-06-20T13:06:07.417

1

@AdmBorkBork Thank you! I'm new to this so welcome all pointers. This worked well in real life -- amped to see how it plays out here

– Tyler Barron – 2018-06-20T16:55:45.057

@NathanMerrill Thank you for the clarification / suggestion! I'll add the bots below soon. I'm torn on the # of games... obviously you want more to be deterministic... I felt like the 100 per 10 was a decent way to get 20 games / person. I'd be down to double or triple it but not much more than that – Tyler Barron – 2018-06-20T16:57:55.617

@KevinCruijssen I added a quick "How To Play" section. The game is nearly no differences from the board game which may be easier since you can see the concepts visually – Tyler Barron – 2018-06-20T17:11:58.320

Answers

1

Sir_Humpfree_Bogart.py

This is a bot I made for the Camel Up Cup Tournament.

First, they look at all the possible configurations that the camels could end up at the end of the round. Then they determine the expected value of betting on a camel winning the round using

EV_roundwin = (chance_1st)*(payout) + (chance_2nd)*(payout) - (chance_3rd_or_worse)*(cost)

Then they move camels randomly until a camel wins. After doing this a few thousand times you can estimate the chance each camel will win and lose. Again, we get the expected value of these using

EV_gamewin = (chance_1st)*(payout) - (chance_2nd_or_worse)*(cost)

The only other options are moving a camel (which always yields one coin, so its expected value is one) and placing a trap. Both teams felt placing a trap was a weak enough option to ignore it entirely. With this information the bots chose the option with the highest expected value.

Since the tournament viewed a second place finish the same as a last place finish it makes sense if you are behind to take chances to get into first place. SBH used distance_from_first_place and nearness_to_end to determine how risky the bot should be, where if you are far from first and close to the end then riskiness would be high and if you are in first or far from the end of the game the riskiness would be low. With a low riskiness the bot would decide on an action with a high expected value option and a high riskiness yielding the option with a high upshot. The exact equation was

Functional_EV = EV + (upshot-EV) * riskiness

where upshot is the highest payout you can get from a decision and riskiness ranges from 0 to 1.

Tyler Barron

Posted 2018-06-20T04:27:12.827

Reputation: 181

0

players.py

These are incredibly dumb bots to get the tournament going. They have nearly no logic but act as frameworks for people to use

import random
import math
from playerinterface import PlayerInterface

class Player0(PlayerInterface):
    def move(player,g):
        #This dumb player always moves a camel
        return [0]

class Player1(PlayerInterface):
    def move(player,g):
        #This player is less dumb. If they have the least amount of money they'll make a round winner bet
        #If they aren't in last then they'll place a trap on a random square. Still p dumb though
        if min(g.player_money_values) == g.player_money_values[player]:
            return [2,random.randint(0,len(g.camels)-1)]
        return [1,math.floor(2*random.random())*2-1,random.randint(1,10)]

class Player2(PlayerInterface):
    def move(player,g):
        #This dumb player always makes a round winner bet
        return [2,random.randint(0,len(g.camels)-1)]

Tyler Barron

Posted 2018-06-20T04:27:12.827

Reputation: 181