Browse Source

Fully port code

master
Jeremy Kescher 7 months ago
parent
commit
3fa12abdc1
10 changed files with 164 additions and 15 deletions
  1. +62
    -0
      cmd/duel.go
  2. +1
    -1
      cmd/fluke.go
  3. +1
    -1
      cmd/loyal.go
  4. +71
    -10
      cmd/main.go
  5. +24
    -0
      cmd/maputils.go
  6. +1
    -0
      cmd/strategy.go
  7. +1
    -1
      cmd/switch.go
  8. +1
    -1
      cmd/tattletale.go
  9. +1
    -1
      go.mod
  10. +1
    -0
      main.go

+ 62
- 0
cmd/duel.go View File

@ -0,0 +1,62 @@
package cmd
import "math/rand"
type DuelResult int
const (
FirstWon DuelResult = 0 //nolint:staticcheck
SecondWon = 1
BothLie = 2
BothConfess = 3
)
type Duel struct {
first *Convict
second *Convict
}
func randomDuel(convicts []Convict) Duel {
first := &convicts[rand.Intn(len(convicts))] //nolint:gosec
second := &convicts[rand.Intn(len(convicts))] //nolint:gosec
for second == first {
second = &convicts[rand.Intn(len(convicts))] //nolint:gosec
}
return Duel{first, second}
}
func (d *Duel) commence() DuelResult {
firstConfessing := d.first.isConfessing()
secondConfessing := d.second.isConfessing()
switch {
case firstConfessing:
if secondConfessing {
return BothConfess
}
return FirstWon
case secondConfessing:
return SecondWon
default:
return BothLie
}
}
func (d *Duel) executeAfterMath(result DuelResult) {
switch result {
case FirstWon:
d.first.afterMath(false)
d.second.strategy = d.first.getNewStrategyInstance()
case SecondWon:
d.second.afterMath(false)
d.first.strategy = d.second.getNewStrategyInstance()
case BothLie:
d.first.afterMath(false)
d.second.afterMath(false)
case BothConfess:
d.first.afterMath(true)
d.second.afterMath(true)
}
}

+ 1
- 1
cmd/fluke.go View File

@ -10,7 +10,7 @@ func (f *Fluke) probability() float64 {
return 0.5000000000000000000000000000000000000000000000000000000000000
}
func (f *Fluke) afterMath(otherConfessed bool) {}
func (f *Fluke) afterMath(_ bool) {}
func (f *Fluke) getNewInstance() Strategy {
return NewFluke()


+ 1
- 1
cmd/loyal.go View File

@ -10,7 +10,7 @@ func (l *Loyal) probability() float64 {
return 0
}
func (l *Loyal) afterMath(otherConfessed bool) {}
func (l *Loyal) afterMath(_ bool) {}
func (l *Loyal) getNewInstance() Strategy {
return NewLoyal()


+ 71
- 10
cmd/main.go View File

@ -2,7 +2,9 @@ package cmd
import (
"math/rand"
"os"
"reflect"
"strconv"
"time"
)
@ -11,16 +13,57 @@ var (
strategyCount = len(strategies)
eachStrategyCount = 5000
convictCount = strategyCount * eachStrategyCount
rounds = convictCount * 5
roundsFactor = 5
rounds = convictCount * roundsFactor
)
func Init() {
// automatically called on import
func init() {
rand.Seed(time.Now().UnixNano())
switchChances[0] = 0.0
switchChances[1] = 1.0
parseAndApplyArgs()
}
func getConvictList() []Convict {
func parseAndApplyArgs() {
for i, arg := range os.Args[1:] {
if i > 1 {
break
}
if arg == "_" {
continue
}
num, err := strconv.Atoi(arg)
if err != nil || num < 1 {
var argName string
switch i {
case 0:
argName = "perStrategy"
case 1:
argName = "roundsFactor"
default:
break
}
println(argName, "is not a valid number, exiting")
} else {
switch i {
case 0:
eachStrategyCount = num
case 1:
roundsFactor = num
default:
// Impossible
break
}
}
}
}
func convictList() []Convict {
var convicts []Convict
addCounts := make(map[string]int)
for _, strategy := range strategies {
@ -29,25 +72,20 @@ func getConvictList() []Convict {
keys := reflect.ValueOf(addCounts).MapKeys()
for len(convicts) < convictCount {
strategyString := keys[rand.Intn(len(keys))].String()
strategyString := keys[rand.Intn(len(keys))].String() //nolint:gosec
var strategy Strategy
switch strategyString {
case "Experience":
strategy = NewExperience()
break
case "Fluke":
strategy = NewFluke()
break
case "Loyal":
strategy = NewLoyal()
break
case "Switch":
strategy = NewSwitch()
break
case "Tattletale":
strategy = NewTattletale()
break
}
count := addCounts[strategyString]
@ -55,6 +93,7 @@ func getConvictList() []Convict {
addCounts[strategyString] = count - 1
} else {
delete(addCounts, strategyString)
keys = reflect.ValueOf(addCounts).MapKeys()
}
convicts = append(convicts, Convict{strategy})
}
@ -62,5 +101,27 @@ func getConvictList() []Convict {
}
func Main() {
Init()
println("Adding", convictCount, "randomly sorted convicts with each available strategy uniformly distributed...")
convicts := convictList()
println("Added!")
println("Now simulating", rounds, "rounds...")
for i := 0; i < rounds; i++ {
duel := randomDuel(convicts)
result := duel.commence()
duel.executeAfterMath(result)
}
statistics := make(map[string]int)
for _, strategy := range strategies {
statistics[strategy] = 0
}
for _, convict := range convicts {
statistics[convict.strategy.String()]++
}
pairList := rankByValue(statistics)
for _, pair := range pairList {
println(pair.k, "represents", pair.v, "convicts")
}
}

+ 24
- 0
cmd/maputils.go View File

@ -0,0 +1,24 @@
package cmd
import "sort"
type Pair struct {
k string
v int
}
type PairList []Pair
func rankByValue(valueMap map[string]int) PairList {
pl := make(PairList, len(valueMap))
i := 0
for k, v := range valueMap {
pl[i] = Pair{k, v}
i++
}
sort.Slice(pl, func(i, j int) bool {
return pl[i].v > pl[j].v
})
return pl
}

+ 1
- 0
cmd/strategy.go View File

@ -6,6 +6,7 @@ type Strategy interface {
probability() float64
afterMath(otherConfessed bool)
getNewInstance() Strategy
String() string
}
func isConfessing(s *Strategy) bool {


+ 1
- 1
cmd/switch.go View File

@ -16,7 +16,7 @@ func (s *Switch) probability() float64 {
return switchChances[s.index]
}
func (s *Switch) afterMath(otherConfessed bool) {
func (s *Switch) afterMath(_ bool) {
if s.index == 0 {
s.index = 1
} else {


+ 1
- 1
cmd/tattletale.go View File

@ -10,7 +10,7 @@ func (t *Tattletale) probability() float64 {
return 1.0
}
func (t *Tattletale) afterMath(otherConfessed bool) {}
func (t *Tattletale) afterMath(_ bool) {}
func (t *Tattletale) getNewInstance() Strategy {
return NewTattletale()


+ 1
- 1
go.mod View File

@ -1,3 +1,3 @@
module git.kescher.at/jeremy.kescher/sim01-in-go
go 1.15
go 1.15

+ 1
- 0
main.go View File

@ -2,6 +2,7 @@ package main
import sim01 "git.kescher.at/jeremy.kescher/sim01-in-go/cmd"
// This main.go is a stub for the underlying sim01.
func main() {
sim01.Main()
}

Loading…
Cancel
Save