func (self *move) adjudicateMovementPhase(r dip.Resolver) error { unit, _, _ := r.Unit(self.targets[0]) convoyed := cla.MustConvoy(r, self.targets[0]) if convoyed { if cla.AnyConvoyPath(r, self.targets[0], self.targets[1], true, nil) == nil { return cla.ErrMissingConvoyPath } } if err := self.adjudicateAgainstCompetition(r, nil); err != nil { return err } var forbiddenSupporter *dip.Nation // at destination if victim, _, hasVictim := r.Unit(self.targets[1]); hasVictim { forbiddenSupporter = &victim.Nation attackStrength := cla.MoveSupport(r, self.targets[0], self.targets[1], []dip.Nation{victim.Nation}) + 1 order, prov, _ := r.Order(self.targets[1]) dip.Logf("'%v' vs '%v': %v", self, order, attackStrength) if order.Type() == cla.Move { victimConvoyed := cla.MustConvoy(r, order.Targets()[0]) if !convoyed && !victimConvoyed && order.Targets()[1].Super() == self.targets[0].Super() { as := cla.MoveSupport(r, order.Targets()[0], order.Targets()[1], []dip.Nation{unit.Nation}) + 1 dip.Logf("'%v' vs '%v': %v", order, self, as) if victim.Nation == unit.Nation || as >= attackStrength { return cla.ErrBounce{self.targets[1]} } } else { dip.Logf("Esc(%v)", order.Targets()[0]) dip.Indent(" ") if err := r.Resolve(prov); err == nil { dip.DeIndent() dip.Logf("Success") forbiddenSupporter = nil } else { dip.DeIndent() dip.Logf("Failure: %v", err) if victim.Nation == unit.Nation || 1 >= attackStrength { return cla.ErrBounce{self.targets[1]} } } } } else { hs := cla.HoldSupport(r, self.targets[1]) + 1 dip.Logf("'%v': %v", order, hs) if victim.Nation == unit.Nation || hs >= attackStrength { return cla.ErrBounce{self.targets[1]} } } } if err := self.adjudicateAgainstCompetition(r, forbiddenSupporter); err != nil { return err } return nil }
func (self *resolver) Resolve(prov common.Province) (err error) { common.Logf("Res(%v) (deps %v)", prov, self.deps) common.Indent(" ") var ok bool if err, ok = self.State.resolutions[prov]; !ok { if err, ok = self.guesses[prov]; !ok { if self.resolving[prov] { common.Logf("Already resolving %v, making negative guess", prov) err = fmt.Errorf("Negative guess") self.guesses[prov] = err self.deps = append(self.deps, prov) } else { self.resolving[prov] = true n_guesses := len(self.guesses) err = self.adjudicate(prov) delete(self.resolving, prov) if _, ok = self.guesses[prov]; ok { common.Logf("Guess made for %v, changing guess to positive", prov) self.guesses[prov] = nil secondErr := self.adjudicate(prov) delete(self.guesses, prov) if (err == nil) != (secondErr == nil) { common.Logf("Calling backup rule with %v", self.deps) if err = self.State.backupRule(self, self.deps); err != nil { return } self.deps = nil err = self.Resolve(prov) } else { common.Logf("Only one consistent result, returning %+v", err) } } else if len(self.guesses) != n_guesses { common.Logf("Made new guess, adding %v to deps", prov) self.deps = append(self.deps, prov) } } } else { common.Logf("Guessed") } if len(self.guesses) == 0 { common.Logf("No guessing, resolving %v", prov) self.State.resolutions[prov] = err } } else { common.Logf("Resolved") } common.DeIndent() if err == nil { common.Logf("%v: Success (deps %v)", prov, self.deps) } else { common.Logf("%v: Failure: %v (deps %v)", prov, err, self.deps) } return }
func (self *resolver) adjudicate(prov common.Province) (err error) { common.Logf("Adj(%v)", prov) common.Indent(" ") err = self.State.orders[prov].Adjudicate(self) common.DeIndent() if err == nil { common.Logf("%v: Success", prov) } else { common.Logf("%v: Failure: %v", prov, err) } return }
func (self *move) adjudicateAgainstCompetition(r dip.Resolver, forbiddenSupporter *dip.Nation) error { _, competingOrders, competingUnits := r.Find(func(p dip.Province, o dip.Order, u *dip.Unit) bool { return o != nil && u != nil && o.Type() == cla.Move && o.Targets()[0] != self.targets[0] && self.targets[1].Super() == o.Targets()[1].Super() }) for index, competingOrder := range competingOrders { var forbiddenSupporters []dip.Nation if forbiddenSupporter != nil { forbiddenSupporters = append(forbiddenSupporters, *forbiddenSupporter) } attackStrength := cla.MoveSupport(r, self.targets[0], self.targets[1], forbiddenSupporters) + 1 dip.Logf("'%v' vs '%v': %v", self, competingOrder, attackStrength) if as := cla.MoveSupport(r, competingOrder.Targets()[0], competingOrder.Targets()[1], nil) + 1; as >= attackStrength { if cla.MustConvoy(r, competingOrder.Targets()[0]) { if cla.AnyConvoyPath(r, competingOrder.Targets()[0], competingOrder.Targets()[1], true, nil) != nil { dip.Logf("'%v' vs '%v': %v", competingOrder, self, as) r.AddBounce(self.targets[0], self.targets[1]) return cla.ErrBounce{competingOrder.Targets()[0]} } } else { dip.Logf("H2HDisl(%v)", self.targets[1]) dip.Indent(" ") if dislodgers, _, _ := r.Find(func(p dip.Province, o dip.Order, u *dip.Unit) bool { res := o != nil && // is an order u != nil && // is a unit o.Type() == cla.Move && // move o.Targets()[1].Super() == competingOrder.Targets()[0].Super() && // against the competition o.Targets()[0].Super() == competingOrder.Targets()[1].Super() && // from their destination u.Nation != competingUnits[index].Nation // not from themselves if res { if !cla.MustConvoy(r, o.Targets()[0]) && r.Resolve(p) == nil { return true } } return false }); len(dislodgers) == 0 { dip.DeIndent() dip.Logf("Not dislodged") dip.Logf("'%v' vs '%v': %v", competingOrder, self, as) r.AddBounce(self.targets[0], self.targets[1]) return cla.ErrBounce{competingOrder.Targets()[0]} } else { dip.DeIndent() dip.Logf("Dislodged by %v", dislodgers) } } } else { dip.Logf("'%v' vs '%v': %v", competingOrder, self, as) } } return nil }