# Farkle Fest 2k19

In this challenge, we will be playing the semi-popular dice game Farkle.

Farkle is a dice game that has players selecting to save dice or risk rerolling the die for more points to add to their total. Players should use probability, game-state considerations and opponent tendency to make their decisions.

## How to play

Rules lifted from this PDF, which includes scoring. There are some differences that you should note after

Each player takes turns rolling the dice. When it's your turn, you roll all six dice at the same time. Points are earned every time you roll a 1 or 5, three of a kind, three pairs, a six-dice straight (1,2,3,4,5,6), or two triplets.

If none of your dice earned points, that's a Farkle! Since you earned no points, you pass the dice to the next player.

If you rolled at least one scoring die, you can bank your points and pass the dice to the next player, or risk the points you just earned during this round by putting some or all of the winning die (dice) aside and rolling the remaining dice. The remaining dice may earn you additional points, but if you Farkle, you lose everything you earned during the round.

If all of your dice contribute to the score you re-roll the dice and add to the points already rolled, but a farkle will lose all the points, including rollover. This is called a "hot-streak"

Scoring is based only on the dice in each roll. You can earn points by combining dice from different rolls. You can continue rolling the dice until you either Pass or Farkle. Then the next player rolls the six dice until they Pass or Farkle. Play continues until it is your turn again.

The final round starts as soon as any player reaches 20,000 or more points.

Scoring:

    five = 50
one = 100
triple 1 = 1000
triple 2 = 200
triple 3 = 300
triple 4 = 400
triple 5 = 500
triple 6 = 600
one thru six = 1500
three pairs = 1500
two triplets = 2500
four of a kind = 1000
five of a kind = 2000
six of a kind = 3000
farkle = 0
three farkles in a row = -1000


Notes:

• There are varying scoring tables. Use the one linked and rewritten above
• Most online versions say something like "You cannot earn points by combining dice from different rolls". This is not how I play. If you roll triple sixes and reroll and end up with another six you now have quad sixes.
• The ending score has been increased from 10,000 to 20,000. This increases the decision points and decreases randomness.
• Some variants have a "threshold to start getting points" (often around 500). This would prevent you from keeping a roll of less than 500 if your score was 0 (or negative). This rule is not in effect.

## Challenge

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

    index (where you sit at the table)
end_score (score required to win (20,000))
game_scores (all the players current score)
state_variable (space for you to put whatever you want)

#round values, these change during the round
round_score (score of the current set of dice)
round_rollover (score from previous "hot streaks")
round_dice (current dice)
round_set_aside (dice you set aside before rolling)


Players should return an array showing which dice they want to set aside. This should be wrapped in a set_dice_aside(self) method

For instance, here's a player that will save dice that add to their score until the score they would get is 500 or greater

class GoForFiveHundred(Bot):
def set_dice_aside(self):
while (self.round_score + self.round_rollover) < 500:
return self.round_used_in_score
return [True, True, True, True, True, True]


## Gameplay

The tournament runner can be found here: Farkle_Fest_2K19. Run main.py to run a tournament. I'll keep it updated with new submissions. Example programs can be found in farkle_bots.py. Lots of code was lifted from maxb, many thanks for that framework and code.

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

## Scoring

The winner of each game is the player with the most points 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 dumb bots 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 ~1s per turn.

Submissions may not duplicate earlier submissions.

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 two month after this question was posted (November 2nd).

Simulation of 5000 games between 5 bots completed in 675.7 seconds Each game lasted for an average of 15.987000 rounds 8 games were tied between two or more bots 0 games ran until the round limit, highest round was 48

+----------------+----+--------+--------+------+------+-------+
|Bot             |Win%|    Wins|  Played|   Max|   Avg|Avg win|
+----------------+----+--------+--------+------+------+-------+
|WaitBot         |95.6|    2894|    3028| 30500| 21988|  22365|
|BruteForceOdds  |38.7|    1148|    2967| 25150| 15157|  20636|
|GoForFiveHundred|19.0|     566|    2981| 24750| 12996|  20757|
|GoForTwoGrand   |13.0|     390|    2997| 25450| 10879|  21352|
|SetAsideAll     | 0.2|       6|    3027| 25200|  7044|  21325|
+----------------+----+--------+--------+------+------+-------+

+----------------+-------+-----+
|Bot             |   Time|Time%|
+----------------+-------+-----+
|BruteForceOdds  |2912.70| 97.0|
|WaitBot         |  58.12|  1.9|
|GoForTwoGrand   |  13.85|  0.5|
|GoForFiveHundred|  10.62|  0.4|
|SetAsideAll     |   7.84|  0.3|
+----------------+-------+-----+


And the results without WaitBot, which I'm still morally undecided on:

+----------------+----+--------+--------+------+------+-------+
|Bot             |Win%|    Wins|  Played|   Max|   Avg|Avg win|
+----------------+----+--------+--------+------+------+-------+
|BruteForceOdds  |72.0|    2698|    3748| 26600| 19522|  20675|
|GoForFiveHundred|37.2|    1378|    3706| 25350| 17340|  20773|
|GoForTwoGrand   |24.3|     927|    3813| 26400| 14143|  21326|
|SetAsideAll     | 0.1|       5|    3733| 21200|  9338|  20620|
+----------------+----+--------+--------+------+------+-------+
+----------------+-------+-----+
|Bot             |   Time|Time%|
+----------------+-------+-----+
|BruteForceOdds  |4792.26| 98.9|
|GoForTwoGrand   |  24.53|  0.5|
|GoForFiveHundred|  18.06|  0.4|
|SetAsideAll     |  13.01|  0.3|
+----------------+-------+-----+

• Is it possible to have access to the score function or something like it, so that people don't have to write their own for every submission?
– Jo King
Sep 3, 2019 at 4:05
• I don't think you reset the number of farkles in a row when a player doesn't get a farkle
– Jo King
Sep 3, 2019 at 6:04
• I've only read the rules once, but can a submission interact with others during a game? If not, this would likely be better as a [code-challenge] or something similar. Sep 3, 2019 at 7:10
• Do you need to put aside at least one die a round? The controller allows putting aside no dice. Also, can you reintroduce dice you have put aside (also allowed)?
– Jo King
Sep 3, 2019 at 8:40
• @Tyler Are you sure it's a good idea to allow 1s per turn? You could be bruteforcing stuff (that is, simulating all your possible moves repeatedly and calculating averages or something), and that'd slow down the game to take a few seconds, and you have thousands of them. I am not sure about [koth] here, but I can see code-challenge has some advantages (for example, it's easier and faster to test and debug). Sep 3, 2019 at 14:40

# BruteForceOdds

Here's that brute force bot:

from main import Controller
from farkle_bots import Bot

scoreDevice = Controller(1, 1, [], 0)

class BruteForceOdds(Bot):
def set_dice_aside(self):
stop_score = self.round_score + self.round_rollover
if self.game_scores[self.index] + stop_score > max(self.game_scores + [self.end_score]):
# Take the win
return [True, True, True, True, True, True]

using = self.round_used_in_score[:]
if self.round_dice.count(5) < 3:
for i in range(len(using)):
if self.round_dice[i] == 5 and not self.round_set_aside[i] and using.count(True) > self.round_set_aside.count(True)+1:
using[i] = False
if self.round_dice.count(1) < 3:
for i in range(len(using)):
if self.round_dice[i] == 1 and not self.round_set_aside[i] and using.count(True) > self.round_set_aside.count(True)+1:
using[i] = False
if using.count(True) < 3 and self.round_rollover == 0:
# Stopping here is basically never a good idea
return using

if bruteScore(self.round_dice, using, self.round_rollover) > stop_score:
return using
return [True, True, True, True, True, True]

def bruteScore(round_dice, set_aside, base_score):
base_dice = []
for i in range(len(round_dice)):
if(set_aside[i]):
base_dice.append(round_dice[i])
totalCount = 0
totalScore = 0
for new_dice in allPossibleRolls(len(round_dice) - len(base_dice)):
dice = base_dice + new_dice
keep = [True]*len(base_dice)+[False]*len(new_dice)
farkle, round_score, round_rollover, used_in_score = scoreDevice.score(dice, keep, base_score)
totalCount += 1
if not farkle:
totalScore += round_score + round_rollover

def allPossibleRolls(length):
if length == 0:
yield []
return
for i in range(1,7):
for l in allPossibleRolls(length-1):
yield [i]+l


It only fares slightly better than the example program GoForFiveHundred.

EDIT: Made it a bit smarter. Now it does noticeably better than any of the example bots.

• Amazing! I'll run it against the other bots later today! Oct 4, 2019 at 11:46
• @TylerBarron Did you do it? I don't see it in the results listed in the question. Oct 6, 2019 at 9:40
• I did later than I hoped. It should have results now! I also may have a few other challengers incoming :) Oct 7, 2019 at 16:08

# WaitBot

class WaitBot(Bot):
def set_dice_aside(self):
return [self.round_rollover+self.round_score > 5000]*6


Try it online!

This basically takes no dice until the total round score is greater than 5000. Really, it's betting on getting hot streaks before farkles.

This wins about 97% of the time when put up against the default three bots.

Edit: Erm, this may not be valid, since you need to putting some or all of the winning die (dice) aside. I'm waiting on confirmation from the asker on this, since the controller allows it.

• I just realised the TIO link you provided is useless without the given classes Sep 16, 2019 at 7:01