Skip to content

Commit

Permalink
Make adjacent convoy resolutions consistent (#134)
Browse files Browse the repository at this point in the history
* Implemented the missing rule "convoyed units can not break support against the convoy".

* Added failing tests.

* Tested the right thing.

* Made 'ViaConvoy' intent and 'owned fleet convoys' intent treated the same way. Also made the Droidippy tests run in parallel.
  • Loading branch information
zond authored Apr 14, 2021
1 parent 1a12456 commit 599055e
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 16 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/zond/godip
go 1.14

require (
github.com/cheggaaa/pb/v3 v3.0.8
github.com/davecgh/go-spew v1.1.1
github.com/gorilla/mux v1.7.4
google.golang.org/appengine v1.6.5
Expand Down
19 changes: 19 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA=
github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
12 changes: 12 additions & 0 deletions godip.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"reflect"
"sort"
"strings"
"sync"
"time"
)

Expand Down Expand Up @@ -156,34 +157,45 @@ func (self ErrBounce) Error() string {
var Debug = false
var LogIndent = []string{}
var logBuffer = new(bytes.Buffer)
var logMutex = sync.RWMutex{}

func Indent(s string) {
if Debug {
logMutex.Lock()
defer logMutex.Unlock()
LogIndent = append(LogIndent, s)
}
}

func DeIndent() {
if Debug {
logMutex.Lock()
defer logMutex.Unlock()
LogIndent = LogIndent[:len(LogIndent)-1]
}
}

func Logf(s string, o ...interface{}) {
if Debug {
logMutex.Lock()
defer logMutex.Unlock()
fmt.Fprintf(logBuffer, fmt.Sprintf("%v%v\n", strings.Join(LogIndent, ""), s), o...)
}
}

func ClearLog() {
if Debug {
logMutex.Lock()
defer logMutex.Unlock()
logBuffer = new(bytes.Buffer)
}
}

func DumpLog() {
if Debug {
logMutex.RLock()
fmt.Print(string(logBuffer.Bytes()))
logMutex.RUnlock()
ClearLog()
}
}
Expand Down
2 changes: 1 addition & 1 deletion orders/convoy.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ func MustConvoy(r godip.Resolver, src godip.Province) bool {
Validator: r,
Source: order.Targets()[0],
Destination: order.Targets()[1],
ResolveConvoys: true,
VerifyConvoyOrders: true,
MinLengthAtDestination: 1,
}}).Any()) > 1) ||
len((ConvoyPathFinder{
Expand Down
142 changes: 142 additions & 0 deletions variants/classical/classical_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -761,3 +761,145 @@ func TestMessages(t *testing.T) {
}
}
}

func TestAdjacentConvoyOtherFleetViaConvoy(t *testing.T) {
judge := Blank(NewPhase(1901, godip.Spring, godip.Movement))
judge.SetUnit("nap", godip.Unit{godip.Army, godip.Italy})
judge.SetUnit("tys", godip.Unit{godip.Fleet, godip.England})
judge.SetUnit("wes", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("ion", godip.Unit{godip.Fleet, godip.France})
judge.SetOrder("nap", orders.Move("nap", "rom").ViaConvoy())
judge.SetOrder("tys", orders.Convoy("tys", "nap", "rom"))
judge.SetOrder("wes", orders.Move("wes", "tys"))
judge.SetOrder("ion", orders.SupportMove("wes", "wes", "tys"))
judge.Next()
if found := judge.Resolutions()["nap"]; found != godip.ErrMissingConvoyPath {
t.Errorf("Wanted failure for nap, got %v", found)
}
if found, ok := judge.Resolutions()["tys"].(godip.ErrConvoyDislodged); !ok {
t.Errorf("Wanted failure for tys, got %v", found)
}
if found := judge.Resolutions()["wes"]; found != nil {
t.Errorf("Wanted success for wes, got %v", found)
}
if found := judge.Resolutions()["ion"]; found != nil {
t.Errorf("Wanted success for ion, got %v", found)
}
}

func TestAdjacentConvoyOtherFleet(t *testing.T) {
judge := Blank(NewPhase(1901, godip.Spring, godip.Movement))
judge.SetUnit("nap", godip.Unit{godip.Army, godip.Italy})
judge.SetUnit("tys", godip.Unit{godip.Fleet, godip.England})
judge.SetUnit("wes", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("ion", godip.Unit{godip.Fleet, godip.France})
judge.SetOrder("nap", orders.Move("nap", "rom"))
judge.SetOrder("tys", orders.Convoy("tys", "nap", "rom"))
judge.SetOrder("wes", orders.Move("wes", "tys"))
judge.SetOrder("ion", orders.SupportMove("wes", "wes", "tys"))
judge.Next()
if found := judge.Resolutions()["nap"]; found != nil {
t.Errorf("Wanted success for nap, got %v", found)
}
if found, ok := judge.Resolutions()["tys"].(godip.ErrConvoyDislodged); !ok {
t.Errorf("Wanted failure for tys, got %v", found)
}
if found := judge.Resolutions()["wes"]; found != nil {
t.Errorf("Wanted success for wes, got %v", found)
}
if found := judge.Resolutions()["ion"]; found != nil {
t.Errorf("Wanted success for ion, got %v", found)
}
}

func TestAdjacentConvoyOtherFleetWithEnemy(t *testing.T) {
judge := Blank(NewPhase(1901, godip.Spring, godip.Movement))
judge.SetUnit("nap", godip.Unit{godip.Army, godip.Italy})
judge.SetUnit("rom", godip.Unit{godip.Army, godip.Germany})
judge.SetUnit("tys", godip.Unit{godip.Fleet, godip.England})
judge.SetUnit("wes", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("ion", godip.Unit{godip.Fleet, godip.France})
judge.SetOrder("rom", orders.Move("rom", "nap"))
judge.SetOrder("nap", orders.Move("nap", "rom"))
judge.SetOrder("tys", orders.Convoy("tys", "nap", "rom"))
judge.SetOrder("wes", orders.Move("wes", "tys"))
judge.SetOrder("ion", orders.SupportMove("wes", "wes", "tys"))
judge.Next()
if found, ok := judge.Resolutions()["nap"].(godip.ErrBounce); !ok {
t.Errorf("Wanted failure for nap, got %v", found)
}
if found, ok := judge.Resolutions()["tys"].(godip.ErrConvoyDislodged); !ok {
t.Errorf("Wanted failure for tys, got %v", found)
}
if found := judge.Resolutions()["wes"]; found != nil {
t.Errorf("Wanted success for wes, got %v", found)
}
if found := judge.Resolutions()["ion"]; found != nil {
t.Errorf("Wanted success for ion, got %v", found)
}
}

func TestAdjacentConvoyOwnFleet(t *testing.T) {
judge := Blank(NewPhase(1901, godip.Spring, godip.Movement))
judge.SetUnit("nap", godip.Unit{godip.Army, godip.Italy})
judge.SetUnit("tys", godip.Unit{godip.Fleet, godip.Italy})
judge.SetUnit("wes", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("ion", godip.Unit{godip.Fleet, godip.France})
judge.SetOrder("nap", orders.Move("nap", "rom"))
judge.SetOrder("tys", orders.Convoy("tys", "nap", "rom"))
judge.SetOrder("wes", orders.Move("wes", "tys"))
judge.SetOrder("ion", orders.SupportMove("wes", "wes", "tys"))
judge.Next()
if found := judge.Resolutions()["nap"]; found != godip.ErrMissingConvoyPath {
t.Errorf("Wanted failure for nap, got %v", found)
}
if found, ok := judge.Resolutions()["tys"].(godip.ErrConvoyDislodged); !ok {
t.Errorf("Wanted failure for tys, got %v", found)
}
if found := judge.Resolutions()["wes"]; found != nil {
t.Errorf("Wanted success for wes, got %v", found)
}
if found := judge.Resolutions()["ion"]; found != nil {
t.Errorf("Wanted success for ion, got %v", found)
}
}

func TestAdjacentConvoyOwnFleetUnnecessaryParticipant(t *testing.T) {
judge := Blank(NewPhase(1901, godip.Spring, godip.Movement))
judge.SetUnit("wal", godip.Unit{godip.Army, godip.England})
judge.SetUnit("eng", godip.Unit{godip.Fleet, godip.England})
judge.SetUnit("nrg", godip.Unit{godip.Fleet, godip.England})
judge.SetUnit("iri", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("nao", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("nth", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("ska", godip.Unit{godip.Fleet, godip.Germany})
judge.SetUnit("hel", godip.Unit{godip.Fleet, godip.Germany})
judge.SetOrder("wal", orders.Move("wal", "lon"))
judge.SetOrder("nrg", orders.Convoy("nrg", "wal", "lon"))
judge.SetOrder("ska", orders.Move("ska", "nth"))
judge.SetOrder("hel", orders.SupportMove("ska", "ska", "nth"))
judge.Next()
if found := judge.Resolutions()["wal"]; found != godip.ErrMissingConvoyPath {
t.Errorf("Wanted failure for wal, got %v", found)
}
}

func TestAdjacentConvoyOwnFleetUnnecessaryParticipantDislodged(t *testing.T) {
judge := Blank(NewPhase(1901, godip.Spring, godip.Movement))
judge.SetUnit("wal", godip.Unit{godip.Army, godip.England})
judge.SetUnit("eng", godip.Unit{godip.Fleet, godip.England})
judge.SetUnit("nrg", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("iri", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("nao", godip.Unit{godip.Fleet, godip.France})
judge.SetUnit("nth", godip.Unit{godip.Fleet, godip.England})
judge.SetUnit("ska", godip.Unit{godip.Fleet, godip.Germany})
judge.SetUnit("hel", godip.Unit{godip.Fleet, godip.Germany})
judge.SetOrder("wal", orders.Move("wal", "lon"))
judge.SetOrder("nth", orders.Convoy("nrg", "wal", "lon"))
judge.SetOrder("ska", orders.Move("ska", "nth"))
judge.SetOrder("hel", orders.SupportMove("ska", "ska", "nth"))
judge.Next()
if found := judge.Resolutions()["wal"]; found != godip.ErrMissingConvoyPath {
t.Errorf("Wanted failure for wal, got %v", found)
}
}
41 changes: 26 additions & 15 deletions variants/testing/games_testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"testing"
"time"

"github.com/cheggaaa/pb/v3"
"github.com/zond/godip"
"github.com/zond/godip/orders"
"github.com/zond/godip/state"
Expand Down Expand Up @@ -271,25 +272,35 @@ func TestGames(t *testing.T, variant common.Variant) {
t.Fatalf("%v", err)
}
sort.Sort(sort.StringSlice(gamefiles))
bar := pb.StartNew(len(gamefiles))
for _, name := range gamefiles {
if skip := os.Getenv("SKIP"); skip == "" || bytes.Compare([]byte(skip), []byte(name)) < 1 {
if gameFileReg.MatchString(name) {
fmt.Printf("Testing %v %v\n", variant.Name, name)
phases, orders, positions, fails, s := assertGame(t, name, variant.Nations, variant.Start, variant.Blank, variant.Parser.Parse)
if os.Getenv("DEBUG") == "true" {
fmt.Printf("Checked %v phases, executed %v orders and asserted %v positions in %v, found %v failures.\n", phases, orders, positions, name, fails)
}
if os.Getenv("BENCHMARK_OPTIONS") == "true" {
fmt.Printf("Spent on average %v calculating options, never more than %v.", timeSpentCalculatingOptions/time.Duration(optionsCalculated), worstOptionsCalculation)
}
if fails > 0 {
godip.DumpLog()
for prov, err := range s.Resolutions() {
t.Errorf("%v: %v", prov, err)
}
t.Fatalf("%v failed!", name)
}
func(name string) {
t.Run(fmt.Sprintf("%v %v", variant.Name, name), func(t *testing.T) {
t.Parallel()
phases, orders, positions, fails, s := assertGame(t, name, variant.Nations, variant.Start, variant.Blank, variant.Parser.Parse)
if os.Getenv("DEBUG") == "true" {
fmt.Printf("Checked %v phases, executed %v orders and asserted %v positions in %v, found %v failures.\n", phases, orders, positions, name, fails)
}
if os.Getenv("BENCHMARK_OPTIONS") == "true" {
fmt.Printf("Spent on average %v calculating options, never more than %v.", timeSpentCalculatingOptions/time.Duration(optionsCalculated), worstOptionsCalculation)
}
if fails > 0 {
godip.DumpLog()
for prov, err := range s.Resolutions() {
t.Errorf("%v: %v", prov, err)
}
t.Fatalf("%v failed!", name)
}
bar.Increment()
})
}(name)
} else {
bar.Increment()
}
} else {
bar.Increment()
}
}
}

0 comments on commit 599055e

Please sign in to comment.