func BackupRule(state dip.State, deps []dip.Province) (err error) { only_moves := true convoys := false for _, prov := range deps { if order, _, ok := state.Order(prov); ok { if order.Type() != cla.Move { only_moves = false } if order.Type() == cla.Convoy { convoys = true } } } if only_moves { for _, prov := range deps { state.SetResolution(prov, nil) } return } if convoys { for _, prov := range deps { if order, _, ok := state.Order(prov); ok && order.Type() == cla.Convoy { state.SetResolution(prov, cla.ErrConvoyParadox) } } return } err = fmt.Errorf("Unknown circular dependency between %v", deps) return }
func (self *move) Execute(state dip.State) { if state.Phase().Type() == cla.Retreat { state.Retreat(self.targets[0], self.targets[1]) } else { state.Move(self.targets[0], self.targets[1], !cla.MustConvoy(state, self.targets[0])) } }
func (self *disband) Execute(state dip.State) { if state.Phase().Type() == cla.Adjustment { state.RemoveUnit(self.targets[0]) } else { state.RemoveDislodged(self.targets[0]) } }
func (self *phase) sortedUnits(s dip.State, n dip.Nation) (result []dip.Province, err error) { provs := remoteUnitSlice{ distances: make(map[dip.Province]int), units: make(map[dip.Province]dip.Unit), } provs.provinces, _, _ = s.Find(func(p dip.Province, o dip.Order, u *dip.Unit) bool { if u != nil && u.Nation == n { if provs.distances[p], err = self.shortestDistance(s, p, s.Graph().SCs(n)); err != nil { return false } provs.units[p] = *u return true } return false }) if err != nil { return } sort.Sort(provs) dip.Logf("Sorted units for %v is %v", n, provs) result = provs.provinces return }
func (self *phase) shortestDistance(s dip.State, src dip.Province, dst []dip.Province) (result int, err error) { var unit dip.Unit var ok bool unit, src, ok = s.Unit(src) if !ok { err = fmt.Errorf("No unit at %v", src) return } var filter dip.PathFilter found := false for _, destination := range dst { if unit.Type == cla.Fleet { filter = func(p dip.Province, edgeFlags, nodeFlags map[dip.Flag]bool, sc *dip.Nation) bool { return edgeFlags[cla.Sea] && nodeFlags[cla.Sea] } } else { filter = func(p dip.Province, edgeFlags, nodeFlags map[dip.Flag]bool, sc *dip.Nation) bool { if p.Super() == destination.Super() { return true } u, _, ok := s.Unit(p) return (edgeFlags[cla.Land] && nodeFlags[cla.Land]) || (ok && !nodeFlags[cla.Land] && u.Nation == unit.Nation && u.Type == cla.Fleet) } } for _, coast := range s.Graph().Coasts(destination) { for _, srcCoast := range s.Graph().Coasts(src) { if srcCoast == destination { result = 0 found = true } else { if path := s.Graph().Path(srcCoast, coast, filter); path != nil { if !found || len(path) < result { result = len(path) found = true } } if path := s.Graph().Path(srcCoast, coast, nil); path != nil { if !found || len(path) < result { result = len(path) found = true } } } } } } return }
func (self *phase) PostProcess(s dip.State) (err error) { if self.typ == cla.Retreat { for prov, _ := range s.Dislodgeds() { s.RemoveDislodged(prov) s.SetResolution(prov, cla.ErrForcedDisband) } s.ClearDislodgers() s.ClearBounces() if self.season == cla.Fall { s.Find(func(p dip.Province, o dip.Order, u *dip.Unit) bool { if u != nil { if s.Graph().SC(p) != nil { s.SetSC(p.Super(), u.Nation) } } return false }) } } else if self.typ == cla.Adjustment { for _, nationality := range cla.Nations { _, _, balance := cla.AdjustmentStatus(s, nationality) if balance < 0 { var su []dip.Province if su, err = self.sortedUnits(s, nationality); err != nil { return } su = su[:-balance] for _, prov := range su { dip.Logf("Removing %v due to forced disband", prov) s.RemoveUnit(prov) s.SetResolution(prov, cla.ErrForcedDisband) } } } } else if self.typ == cla.Movement { for prov, unit := range s.Dislodgeds() { hasRetreat := false for edge, _ := range s.Graph().Edges(prov) { if _, _, ok := s.Unit(edge); !ok && !s.Bounce(prov, edge) { if cla.HasEdge(s, unit.Type, prov, edge) { dip.Logf("%v can retreat to %v", prov, edge) hasRetreat = true break } } } if !hasRetreat { s.RemoveDislodged(prov) dip.Logf("Removing %v since it has no retreat", prov) } } } return }