From cd3b84709884ad2c1143a420252ff280c6c0f6ab Mon Sep 17 00:00:00 2001 From: Bastian Kennel Date: Tue, 3 Mar 2015 19:36:30 +0100 Subject: [PATCH 1/7] es ist schnell und es terminiert, aber ist es auch richtig?? Die Zahlen von den Homepagen bekomme ich nicht. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Und 0,3% erscheint mir auch zu wenig ... Anna hat viel öfter ein Yathzee --- probability.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 probability.py diff --git a/probability.py b/probability.py new file mode 100644 index 0000000..95d9b19 --- /dev/null +++ b/probability.py @@ -0,0 +1,38 @@ +from math import factorial as fac + +def out_of(n, r): + return fac(n) / (fac(n-r) * fac(r)) + +class DiceAnalyzer(): + + def prob(self, initial=0, left=4): + free = 5 - initial + result = 0 + # the first option is to hit all now in this throw + result += (1./6 ** free) + # if this is the first dice, then actually you will always hit + if initial == 0: + result *= 6 + # if no more options are left, than that's it + if left == 0: + return result + # there is still hope == throws left + if free > 4: + # if we have all dices free, we can have 4 matches now and still go on + result += (1./6 ** 4) * (5./6 ** 1) * 5 * self.prob(initial + 4, left - 1) + if free > 3: + # with 4 dices, we can draw three now and go on + result += (1./6 ** 3) * (5./6 ** (free-3)) * out_of(free, 3) * self.prob(initial + 3, left - 1) + if free > 2: + # two matches possible with 3 dices + result += (1./6 ** 2) * (5./6 ** (free-2)) * out_of(free, 2) * self.prob(initial + 2, left - 1) + if free > 1: + # we can have one match + result += 1./6 * (5./6 ** (free-1)) * free * self.prob(initial + 1, left - 1) + # any given sunday, we can have no luck + result += 5./6 ** free * self.prob(initial, left - 1) + return result + +if __name__ == "__main__": + da = DiceAnalyzer() + print da.prob() \ No newline at end of file From 2aac3f27c2889283bebbed93f5cd0e82cb085545 Mon Sep 17 00:00:00 2001 From: Bastian Kennel Date: Sun, 8 Mar 2015 19:48:03 +0100 Subject: [PATCH 2/7] Finished 1000000 attempts. Hits: 38855 . Probability of 0.038855 Error 0.038855 Finished 2000000 attempts. Hits: 77514 . Probability of 0.038757 Error 9.8e-05 Finished 3000000 attempts. Hits: 116415 . Probability of 0.038805 Error 4.8e-05 Finished 4000000 attempts. Hits: 155630 . Probability of 0.0389075 Error 0.0001025 Finished 5000000 attempts. Hits: 194814 . Probability of 0.0389628 Error 5.53e-05 Finished 6000000 attempts. Hits: 233627 . Probability of 0.0389378333333 Error 2.49666666667e-05 Finished 7000000 attempts. Hits: 272764 . Probability of 0.0389662857143 Error 2.84523809524e-05 Finished 8000000 attempts. Hits: 311917 . Probability of 0.038989625 Error 2.33392857143e-05 Finished 9000000 attempts. Hits: 350817 . Probability of 0.0389796666667 Error 9.95833333333e-06 Result 0.0389796666667 with 9000000 attempts --- cuatro.py | 6 +++++ player.py | 3 +++ probability.py | 61 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/cuatro.py b/cuatro.py index 3cc046c..3b6fde3 100644 --- a/cuatro.py +++ b/cuatro.py @@ -20,6 +20,8 @@ def __init__(self): self.throws = 0 self.faces = [0, 0, 0, 0, 0] self.counts = {} + self.max_count = 0 + self.max_face = 0 def roll(self, keep=None): # making sure only existing faces are kept @@ -44,6 +46,10 @@ def _update_counts(self): self.counts = defaultdict(int) for num in self.faces: self.counts[num] += 1 + for (face,count) in self.counts.items(): + if count > self.max_count: + self.max_count = count + self.max_face = face def verify(self, keep): """ verifies that keep only contains existing faces """ diff --git a/player.py b/player.py index b98ebdf..70996f2 100644 --- a/player.py +++ b/player.py @@ -1,3 +1,4 @@ +from probability import DiceAnalyzer class Player: """ Base class of a cuatro player """ @@ -25,6 +26,8 @@ def __init__(self, name): def play(self, dice, board): print board print dice.throws, "\t", dice + da = DiceAnalyzer(dice) + da.probability_yahtzee() keep = raw_input("which numbers do you want to keep? ") return [int(k) for k in keep if k.isdigit()] diff --git a/probability.py b/probability.py index 95d9b19..01f0083 100644 --- a/probability.py +++ b/probability.py @@ -5,7 +5,7 @@ def out_of(n, r): class DiceAnalyzer(): - def prob(self, initial=0, left=4): + def yathzee(self, initial=0, left=4): free = 5 - initial result = 0 # the first option is to hit all now in this throw @@ -19,20 +19,65 @@ def prob(self, initial=0, left=4): # there is still hope == throws left if free > 4: # if we have all dices free, we can have 4 matches now and still go on - result += (1./6 ** 4) * (5./6 ** 1) * 5 * self.prob(initial + 4, left - 1) + result += (1./6 ** 4) * (5./6 ** 1) * 5 * self.yathzee(initial + 4, left - 1) if free > 3: # with 4 dices, we can draw three now and go on - result += (1./6 ** 3) * (5./6 ** (free-3)) * out_of(free, 3) * self.prob(initial + 3, left - 1) + result += (1./6 ** 3) * (5./6 ** (free-3)) * out_of(free, 3) * self.yathzee(initial + 3, left - 1) if free > 2: # two matches possible with 3 dices - result += (1./6 ** 2) * (5./6 ** (free-2)) * out_of(free, 2) * self.prob(initial + 2, left - 1) + result += (1./6 ** 2) * (5./6 ** (free-2)) * out_of(free, 2) * self.yathzee(initial + 2, left - 1) if free > 1: # we can have one match - result += 1./6 * (5./6 ** (free-1)) * free * self.prob(initial + 1, left - 1) + result += 1./6 * (5./6 ** (free-1)) * free * self.yathzee(initial + 1, left - 1) # any given sunday, we can have no luck - result += 5./6 ** free * self.prob(initial, left - 1) + result += 5./6 ** free * self.yathzee(initial, left - 1) return result + #def full_house(self, initial=[], left=4) + +def is_yathzee(faces): + face = faces[0] + for f in faces: + if f != face: + return False + return True + +import cuatro + +def simulate_yathzee(): + attempts = 0 + probability = 0 + prev_probability = 0 + hits = 0 + stepsize = 1000000 + error = 1 + while error > 1.0 / 100000: + for attempt in range(stepsize): + attempts += 1 + yathzee = False + dice = cuatro.Dice() + face = 0 + keep= [] + for throw in range(5): + dice.roll(keep) + if face == 0: + face = dice.max_face + else: + keep = [face for i in range(dice.max_count)] + if is_yathzee(dice.faces): + yathzee = True + break + if yathzee: + hits += 1 + prev_probability = probability + probability = hits * 1.0 / attempts + error = abs(probability - prev_probability) + print "Finished ", attempts, " attempts. Hits: ", hits, ". Probability of ", (hits * 1.0 /attempts), " Error ", error + print "Result ", probability, " with ", attempts, " attempts" + + + if __name__ == "__main__": - da = DiceAnalyzer() - print da.prob() \ No newline at end of file + #da = DiceAnalyzer() + #print da.yathzee(0,1) + simulate_yathzee() \ No newline at end of file From 7e841dc864ed0725844ba22db862a366fce81877 Mon Sep 17 00:00:00 2001 From: Bastian Kennel Date: Tue, 10 Mar 2015 18:06:46 +0100 Subject: [PATCH 3/7] merge preparation --- probability.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/probability.py b/probability.py index 01f0083..b041efe 100644 --- a/probability.py +++ b/probability.py @@ -9,31 +9,33 @@ def yathzee(self, initial=0, left=4): free = 5 - initial result = 0 # the first option is to hit all now in this throw - result += (1./6 ** free) + result += ((1./6) ** free) # if this is the first dice, then actually you will always hit if initial == 0: result *= 6 # if no more options are left, than that's it if left == 0: return result - # there is still hope == throws left + # there is still hope == throws + # eaxmine what can happen in this throw and branch if free > 4: # if we have all dices free, we can have 4 matches now and still go on - result += (1./6 ** 4) * (5./6 ** 1) * 5 * self.yathzee(initial + 4, left - 1) + result += ((1./6) ** 4) * ((5./6) ** 1) * 5 * self.yathzee(initial + 4, left - 1) if free > 3: # with 4 dices, we can draw three now and go on - result += (1./6 ** 3) * (5./6 ** (free-3)) * out_of(free, 3) * self.yathzee(initial + 3, left - 1) + result += ((1./6) ** 3) * ((5./6) ** (free-3)) * out_of(free, 3) * self.yathzee(initial + 3, left - 1) if free > 2: # two matches possible with 3 dices - result += (1./6 ** 2) * (5./6 ** (free-2)) * out_of(free, 2) * self.yathzee(initial + 2, left - 1) + result += ((1./6) ** 2) * ((5./6) ** (free-2)) * out_of(free, 2) * self.yathzee(initial + 2, left - 1) if free > 1: # we can have one match - result += 1./6 * (5./6 ** (free-1)) * free * self.yathzee(initial + 1, left - 1) + result += 1./6 * ((5./6) ** (free-1)) * free * self.yathzee(initial + 1, left - 1) # any given sunday, we can have no luck result += 5./6 ** free * self.yathzee(initial, left - 1) return result - #def full_house(self, initial=[], left=4) + def full_house(self, dice): + def is_yathzee(faces): face = faces[0] @@ -78,6 +80,6 @@ def simulate_yathzee(): if __name__ == "__main__": - #da = DiceAnalyzer() - #print da.yathzee(0,1) - simulate_yathzee() \ No newline at end of file + da = DiceAnalyzer() + print da.yathzee() + #simulate_yathzee() \ No newline at end of file From 87479925abf09520c02f82d3fbfdd2918062d89b Mon Sep 17 00:00:00 2001 From: Bastian Kennel Date: Tue, 10 Mar 2015 18:10:21 +0100 Subject: [PATCH 4/7] =?UTF-8?q?moving=20probability=E2=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- probability.py => cuatro/probability.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename probability.py => cuatro/probability.py (100%) diff --git a/probability.py b/cuatro/probability.py similarity index 100% rename from probability.py rename to cuatro/probability.py From 072d95ce21ebb4f863449b540ebab670d0b46c00 Mon Sep 17 00:00:00 2001 From: Bastian Kennel Date: Tue, 10 Mar 2015 18:12:46 +0100 Subject: [PATCH 5/7] enhancing the dice to know what the max face and the count is --- cuatro/dice.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cuatro/dice.py b/cuatro/dice.py index 9e9db75..28e3b8a 100644 --- a/cuatro/dice.py +++ b/cuatro/dice.py @@ -16,6 +16,8 @@ def __init__(self): self.throws = 0 self.faces = [0, 0, 0, 0, 0] self.counts = {} + self.max_face = 0 + self.max_count = 0 def roll(self, keep=None): # making sure only existing faces are kept @@ -40,6 +42,10 @@ def _update_counts(self): self.counts = defaultdict(int) for num in self.faces: self.counts[num] += 1 + for face, count in self.counts.items(): + if count > max_count: + max_count = count + max_face = face def verify(self, keep): """ verifies that keep only contains existing faces """ From 556f1b909ab959a826278158d5a767f74a425142 Mon Sep 17 00:00:00 2001 From: Bastian Kennel Date: Tue, 10 Mar 2015 18:21:04 +0100 Subject: [PATCH 6/7] probability is executing again --- cuatro/dice.py | 6 +++--- cuatro/player.py | 5 ++--- cuatro/probability.py | 21 +++++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cuatro/dice.py b/cuatro/dice.py index 28e3b8a..d023724 100644 --- a/cuatro/dice.py +++ b/cuatro/dice.py @@ -43,9 +43,9 @@ def _update_counts(self): for num in self.faces: self.counts[num] += 1 for face, count in self.counts.items(): - if count > max_count: - max_count = count - max_face = face + if count > self.max_count: + self.max_count = count + self.max_face = face def verify(self, keep): """ verifies that keep only contains existing faces """ diff --git a/cuatro/player.py b/cuatro/player.py index 4dace76..a9e4610 100644 --- a/cuatro/player.py +++ b/cuatro/player.py @@ -1,4 +1,3 @@ -from probability import DiceAnalyzer class Player: """ Base class of a cuatro player """ @@ -26,8 +25,8 @@ def __init__(self, name): def play(self, dice, board): print board print dice.throws, "\t", dice - da = DiceAnalyzer(dice) - da.probability_yahtzee() + #da = DiceAnalyzer(dice) + #da.probability_yahtzee() keep = raw_input("which numbers do you want to keep? ") return [int(k) for k in keep if k.isdigit()] diff --git a/cuatro/probability.py b/cuatro/probability.py index b041efe..e62560c 100644 --- a/cuatro/probability.py +++ b/cuatro/probability.py @@ -35,16 +35,17 @@ def yathzee(self, initial=0, left=4): return result def full_house(self, dice): + pass -def is_yathzee(faces): - face = faces[0] - for f in faces: +def is_yathzee(dice): + face = dice.faces[0] + for f in dice.faces: if f != face: return False return True -import cuatro +import dice def simulate_yathzee(): attempts = 0 @@ -57,16 +58,16 @@ def simulate_yathzee(): for attempt in range(stepsize): attempts += 1 yathzee = False - dice = cuatro.Dice() + d = dice.Dice() face = 0 keep= [] for throw in range(5): - dice.roll(keep) + d.roll(keep) if face == 0: - face = dice.max_face + face = d.max_face else: - keep = [face for i in range(dice.max_count)] - if is_yathzee(dice.faces): + keep = [face for i in range(d.max_count)] + if is_yathzee(d): yathzee = True break if yathzee: @@ -82,4 +83,4 @@ def simulate_yathzee(): if __name__ == "__main__": da = DiceAnalyzer() print da.yathzee() - #simulate_yathzee() \ No newline at end of file + simulate_yathzee() \ No newline at end of file From 1df7cf7f4caf28b272e1acf96efdfb61955fae85 Mon Sep 17 00:00:00 2001 From: Bastian Kennel Date: Tue, 10 Mar 2015 20:43:09 +0100 Subject: [PATCH 7/7] working two roll probability but in a dumb way --- cuatro/probability.py | 46 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/cuatro/probability.py b/cuatro/probability.py index e62560c..16f7b79 100644 --- a/cuatro/probability.py +++ b/cuatro/probability.py @@ -28,12 +28,50 @@ def yathzee(self, initial=0, left=4): # two matches possible with 3 dices result += ((1./6) ** 2) * ((5./6) ** (free-2)) * out_of(free, 2) * self.yathzee(initial + 2, left - 1) if free > 1: + #if free < 5: + # there already is a chosen face # we can have one match result += 1./6 * ((5./6) ** (free-1)) * free * self.yathzee(initial + 1, left - 1) # any given sunday, we can have no luck - result += 5./6 ** free * self.yathzee(initial, left - 1) + result += ((5./6) ** free) * self.yathzee(initial, left - 1) return result + def single_roll(self, target): + if target == "yathzee": + return 6 * (1./6) ** 5 + if target == "four of a kind": + return 6 * 5 * (1./6) ** 4 * 5./6 + if target == "three of a kind": + return 6 * out_of(5,3) * (1./6) ** 3 * (5./6) ** 2 + if target == "pair": + # a true pair, so no full house + return 6 * out_of(5,2) * (1./6) ** 2 * (5./6) ** 2 * 4./6 + if target == "no match": + return fac(6) * 1. / (6 ** 5) + + def y(self, roles=0): + single_roll = self.single_roll("yathzee") + if roles == 1: + return single_roll + # now with two rolls + # four of a kind with a single + four_single = self.single_roll("four of a kind") * (1./6) + # three of a kind and then two matching + three_two = self.single_roll("three of a kind") * (1./6) ** 2 + # a pair and then three that match + pair_three = self.single_roll("pair") * (1./6) ** 3 + # no match and then matching four + no_four = self.single_roll("no match") * (1./6) ** 4 + two_roll = four_single + two_roll += three_two + two_roll += no_four + two_roll += pair_three + if roles == 2: + return two_roll + return single_roll + two_roll + + + def full_house(self, dice): pass @@ -82,5 +120,7 @@ def simulate_yathzee(): if __name__ == "__main__": da = DiceAnalyzer() - print da.yathzee() - simulate_yathzee() \ No newline at end of file + print da.single_roll("yathzee") + print da.y() + #print da.yathzee(0,0) + #simulate_yathzee() \ No newline at end of file