Concurrency seems to work well; cleaned up seq a bit
[bills-tools.git] / seq / examples / dice.go
blob534de3af33648b721dd406da11b3dc45ab0dd65a
1 // Copyright 2010 Bill Burdick. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 //
5 // dice is a program that uses seq to calculate some probabilities for a game:
6 // each player rolls 3 dice, each of which can have 4, 6, 8, or 10 sides
7 // then, they compare the maximum numbers. The one with the highest number wins
8 // this program calculates probabilities of winning by a certain margin (which can be from 1 - 9)
9 package main
11 import "fmt"
12 import "io"
13 import "bytes"
14 import "container/vector"
15 import "sort"
16 import . "github.com/zot/bills-tools/seq"
17 //import "reflect"
19 func add(i int, s Seq) Seq {
20 return s.Map(func(el El)El {
21 return i + el.(int)
25 func max(a, b int) int {
26 if a > b {
27 return a
29 return b
32 func main() {
33 d4 := add(1, AUpto(4))
34 d6 := add(1, AUpto(6))
35 d8 := add(1, AUpto(8))
36 d10 := add(1, AUpto(10))
37 names := map[interface{}]string{d4:"d4", d6:"d6", d8:"d8", d10:"d10"}
38 dice := From(d4, d6, d8, d10)
39 rank := map[Seq]int{d4:0, d6:1, d8:2, d10:3}
40 sets := map[string]int{}
41 //attempts is [[label, [score, ...]]...]
42 attempts := Map(Filter(Product(From(dice, dice, dice)), func(d El)bool{
43 oldRank := -1
44 result := true
45 Do(d.(Seq), func(set El){
46 newRank := rank[set.(Seq)]
47 result = result && newRank >= oldRank
48 oldRank = newRank
50 return result
51 }), func(el El)El{
52 buf := bytes.NewBuffer(make([]byte, 0, 10))
53 io.WriteString(buf, "<")
54 Pretty(el.(Seq), names, buf)
55 io.WriteString(buf, ">")
56 return From(buf.String(), Map(Product(el.(Seq)), func(el El)El{
57 return Fold(el.(Seq), 0, func(acc, el El)El{return max(acc.(int), el.(int))})
58 }))
61 println("#sets:", len(sets))
62 fmt.Println("#Attempts:", Len(attempts))
63 println("results...")
64 Do(attempts, func(el El){
65 label, rolls := First2(el.(Seq))
66 fmt.Printf("%s: %d\n", label, Len(rolls.(Seq)))
68 Do(CFlatMap(attempts, func(el El) Seq {
69 label, sc := First2(el.(Seq))
70 return CMap(attempts, func(del El) El {
71 rolls, wins := 0, 0
72 margins := map[int]int{}
73 dlabel, dsc := First2(del.(Seq))
74 Do(Product(From(sc,dsc)), func(rel El){
75 rolls++
76 attack, defense := First2(rel.(Seq))
77 margin := attack.(int) - defense.(int)
78 if margin > 0 {
79 wins++
80 margins[margin]++
84 return From(label, dlabel, rolls, wins, margins)
86 }), func(el El){
87 l, d, r, w, m := First5(el.(Seq))
88 printResult(l.(string), d.(string), r.(int), w.(int), m.(map[int]int))
92 func printResult(label string, dlabel string, rolls int, wins int, margins map[int]int) {
93 fmt.Printf("%s vs %s rolls: %d wins: %d margins:", label, dlabel, rolls, wins)
94 for i := 1; i <= 9; i++ {
95 v := margins[i]
96 if v > 0 {
97 fmt.Printf(" %d %.2f", v, float(v)*100/float(wins))
100 println()
101 dumpMargin(wins, margins)
105 func round(value float) int {
106 floor := int(value)
107 if value - float(floor) > 0.5 {
108 if value > 0 {
109 return floor + 1
111 return floor - 1
113 return floor
116 func dumpMargin(totMargin int, margins map[int]int) {
117 for k := 1; k <= 9; k++ {
118 v := margins[k]
119 if v > 0 {
120 percent := float(v)*100/float(totMargin)
121 fmt.Printf("%d: %10d (%6.2f) ", k, v, percent)
122 for i := 0; i < int(round(percent)); i++ {
123 print(".")
125 println()
129 func dumpResults(totMargin int, margins map[string]map[int]int) {
130 vec := vector.StringVector(make([]string, 0, 32))
131 for k := range margins {
132 vec.Push(k)
134 sort.StringArray(vec).Sort()
135 for _, dice := range vec {
136 println("Margins for", dice)
137 dumpMargin(totMargin, margins[dice])