module Diplomacy.OrderValidation (
ValidityCharacterization(..)
, ArgumentList(..)
, ValidityCriterion(..)
, SomeValidityCriterion(..)
, AdjustSetValidityCriterion(..)
, ValidityTag
, AdjustSetValidityTag
, synthesize
, analyze
, moveVOC
, supportVOC
, convoyVOC
, surrenderVOC
, withdrawVOC
, AdjustSubjects(..)
, disbandSubjectVOC
, buildSubjectVOC
, continueSubjectVOC
, adjustSubjectsVOC
) where
import GHC.Exts (Constraint)
import Control.Monad
import Control.Applicative
import qualified Data.Map as M
import qualified Data.Set as S
import Data.MapUtil
import Data.AtLeast
import Data.Functor.Identity
import Data.Functor.Constant
import Data.Functor.Compose
import Data.List as L
import Diplomacy.GreatPower
import Diplomacy.Aligned
import Diplomacy.Unit
import Diplomacy.Phase
import Diplomacy.Subject
import Diplomacy.OrderType
import Diplomacy.OrderObject
import Diplomacy.Order
import Diplomacy.Province
import Diplomacy.Zone
import Diplomacy.ZonedSubject
import Diplomacy.Occupation
import Diplomacy.Dislodgement
import Diplomacy.Control
import Diplomacy.SupplyCentreDeficit
import Diplomacy.OrderResolution
import Debug.Trace
data ValidityCriterion (phase :: Phase) (order :: OrderType) where
MoveValidSubject :: ValidityCriterion Typical Move
MoveUnitCanOccupy :: ValidityCriterion Typical Move
MoveReachable :: ValidityCriterion Typical Move
SupportValidSubject :: ValidityCriterion Typical Support
SupporterAdjacent :: ValidityCriterion Typical Support
SupporterCanOccupy :: ValidityCriterion Typical Support
SupportedCanDoMove :: ValidityCriterion Typical Support
ConvoyValidSubject :: ValidityCriterion Typical Convoy
ConvoyValidConvoySubject :: ValidityCriterion Typical Convoy
ConvoyValidConvoyTarget :: ValidityCriterion Typical Convoy
SurrenderValidSubject :: ValidityCriterion Retreat Surrender
WithdrawValidSubject :: ValidityCriterion Retreat Withdraw
WithdrawAdjacent :: ValidityCriterion Retreat Withdraw
WithdrawUnoccupiedZone :: ValidityCriterion Retreat Withdraw
WithdrawUncontestedZone :: ValidityCriterion Retreat Withdraw
WithdrawNotDislodgingZone :: ValidityCriterion Retreat Withdraw
ContinueValidSubject :: ValidityCriterion Adjust Continue
DisbandValidSubject :: ValidityCriterion Adjust Disband
BuildValidSubject :: ValidityCriterion Adjust Build
deriving instance Show (ValidityCriterion phase order)
deriving instance Eq (ValidityCriterion phase order)
deriving instance Ord (ValidityCriterion phase order)
data SomeValidityCriterion (phase :: Phase) where
SomeValidityCriterion :: ValidityCriterion phase order -> SomeValidityCriterion phase
instance Show (SomeValidityCriterion phase) where
show (SomeValidityCriterion vc) = case vc of
MoveValidSubject -> show vc
MoveUnitCanOccupy -> show vc
MoveReachable -> show vc
SupportValidSubject -> show vc
SupporterAdjacent -> show vc
SupporterCanOccupy -> show vc
SupportedCanDoMove -> show vc
ConvoyValidSubject -> show vc
ConvoyValidConvoySubject -> show vc
ConvoyValidConvoyTarget -> show vc
SurrenderValidSubject -> show vc
WithdrawValidSubject -> show vc
WithdrawAdjacent -> show vc
WithdrawUnoccupiedZone -> show vc
WithdrawUncontestedZone -> show vc
WithdrawNotDislodgingZone -> show vc
ContinueValidSubject -> show vc
DisbandValidSubject -> show vc
BuildValidSubject -> show vc
instance Eq (SomeValidityCriterion phase) where
SomeValidityCriterion vc1 == SomeValidityCriterion vc2 = case (vc1, vc2) of
(MoveValidSubject, MoveValidSubject) -> True
(MoveUnitCanOccupy, MoveUnitCanOccupy) -> True
(MoveReachable, MoveReachable) -> True
(SupportValidSubject, SupportValidSubject) -> True
(SupporterAdjacent, SupporterAdjacent) -> True
(SupporterCanOccupy, SupporterCanOccupy) -> True
(SupportedCanDoMove, SupportedCanDoMove) -> True
(ConvoyValidSubject, ConvoyValidSubject) -> True
(ConvoyValidConvoySubject, ConvoyValidConvoySubject) -> True
(ConvoyValidConvoyTarget, ConvoyValidConvoyTarget) -> True
(SurrenderValidSubject, SurrenderValidSubject) -> True
(WithdrawValidSubject, WithdrawValidSubject) -> True
(WithdrawAdjacent, WithdrawAdjacent) -> True
(WithdrawUnoccupiedZone, WithdrawUnoccupiedZone) -> True
(WithdrawUncontestedZone, WithdrawUncontestedZone) -> True
(WithdrawNotDislodgingZone, WithdrawNotDislodgingZone) -> True
(ContinueValidSubject, ContinueValidSubject) -> True
(DisbandValidSubject, DisbandValidSubject) -> True
(BuildValidSubject, BuildValidSubject) -> True
_ -> False
instance Ord (SomeValidityCriterion phase) where
SomeValidityCriterion vc1 `compare` SomeValidityCriterion vc2 =
show vc1 `compare` show vc2
data AdjustSetValidityCriterion where
RequiredNumberOfDisbands :: AdjustSetValidityCriterion
AdmissibleNumberOfBuilds :: AdjustSetValidityCriterion
OnlyContinues :: AdjustSetValidityCriterion
deriving instance Eq AdjustSetValidityCriterion
deriving instance Ord AdjustSetValidityCriterion
deriving instance Show AdjustSetValidityCriterion
unitCanOccupy :: Unit -> S.Set ProvinceTarget
unitCanOccupy unit = case unit of
Army -> S.map Normal . S.filter (not . isWater) $ S.fromList [minBound..maxBound]
Fleet -> S.fromList $ do
pr <- [minBound..maxBound]
guard (not (isInland pr))
case provinceCoasts pr of
[] -> return $ Normal pr
xs -> fmap Special xs
validMoveAdjacency :: Maybe Occupation -> Subject -> S.Set ProvinceTarget
validMoveAdjacency occupation subject = case subjectUnit subject of
Army -> case occupation of
Nothing -> S.fromList $ neighbours pt
Just o -> (S.fromList $ neighbours pt) `S.union` (S.map Normal (convoyTargets o pr))
Fleet -> S.fromList $ do
n <- neighbours pt
let np = ptProvince n
let ppt = ptProvince pt
guard (not (isCoastal np) || not (isCoastal ppt) || not (null (commonCoasts pt n)))
return n
where
pt = subjectProvinceTarget subject
pr = ptProvince pt
convoyPaths :: Occupation -> Province -> [(Province, [Province])]
convoyPaths occupation pr =
filter ((/=) pr . fst) . fmap (\(x, y, z) -> (x, y : z)) . paths occupiedByFleet pickCoastal . pure $ pr
where
occupiedByFleet pr = case provinceOccupier pr occupation of
Just aunit -> alignedThing aunit == Fleet
_ -> False
pickCoastal pr = if isCoastal pr then Just pr else Nothing
convoyTargets :: Occupation -> Province -> S.Set Province
convoyTargets occupation = S.fromList . fmap fst . convoyPaths occupation
validMoveTargets
:: Maybe Occupation
-> Subject
-> S.Set ProvinceTarget
validMoveTargets maybeOccupation subject =
(validMoveAdjacency maybeOccupation subject)
`S.intersection`
(unitCanOccupy (subjectUnit subject))
validSupportTargets
:: Subject
-> S.Set ProvinceTarget
validSupportTargets subject = S.fromList $ do
x <- S.toList $ validMoveAdjacency Nothing subject
guard (S.member x (unitCanOccupy (subjectUnit subject)))
provinceTargetCluster x
validSupportSubjects
:: Occupation
-> ProvinceTarget
-> ProvinceTarget
-> S.Set Subject
validSupportSubjects occupation source target = M.foldWithKey f S.empty occupation
where
f zone aunit =
if Zone source /= zone
&& (Zone target == zone
|| S.member target (validMoveTargets (Just occupation) subject'))
then S.insert subject'
else id
where
subject' = (alignedThing aunit, zoneProvinceTarget zone)
validConvoyers
:: Maybe GreatPower
-> Occupation
-> S.Set Subject
validConvoyers greatPower = M.foldWithKey f S.empty
where
f zone aunit = case unit of
Fleet -> if isWater (ptProvince pt)
&& ( greatPower == Nothing
|| greatPower == Just (alignedGreatPower aunit)
)
then S.insert (unit, pt)
else id
_ -> id
where
pt = zoneProvinceTarget zone
unit = alignedThing aunit
validConvoySubjects
:: Occupation
-> S.Set Subject
validConvoySubjects = M.foldWithKey f S.empty
where
f zone aunit = if unit == Army && isCoastal (ptProvince pt)
then S.insert (unit, pt)
else id
where
unit = alignedThing aunit
pt = zoneProvinceTarget zone
validConvoyTargets
:: Occupation
-> Subject
-> Subject
-> S.Set ProvinceTarget
validConvoyTargets occupation subjectConvoyer subjectConvoyed =
let allConvoyPaths = convoyPaths occupation prConvoyed
convoyPathsWithThis = filter (elem prConvoyer . snd) allConvoyPaths
in S.fromList (fmap (Normal . fst) convoyPathsWithThis)
where
prConvoyer = ptProvince (subjectProvinceTarget subjectConvoyer)
prConvoyed = ptProvince (subjectProvinceTarget subjectConvoyed)
setOfAllProvinceTargets :: S.Set ProvinceTarget
setOfAllProvinceTargets = S.fromList [minBound..maxBound]
setOfAllZones :: S.Set Zone
setOfAllZones = S.map Zone setOfAllProvinceTargets
zoneSetToProvinceTargetSet :: S.Set Zone -> S.Set ProvinceTarget
zoneSetToProvinceTargetSet = S.fold f S.empty
where
f zone = S.union (S.fromList (provinceTargetCluster (zoneProvinceTarget zone)))
occupiedZones :: Occupation -> S.Set Zone
occupiedZones = S.map (Zone . snd) . S.fromList . allSubjects Nothing
contestedZones
:: M.Map Zone (Aligned Unit, SomeResolved OrderObject Typical)
-> S.Set Zone
contestedZones = M.foldWithKey g S.empty . M.fold f M.empty
where
f :: (Aligned Unit, SomeResolved OrderObject Typical)
-> M.Map Zone Bool
-> M.Map Zone Bool
f (aunit, SomeResolved (object, res)) = case object of
MoveObject pt -> case res of
Just (MoveBounced _) -> M.alter alteration (Zone pt)
_ -> id
where
alteration (Just bool) = case res of
Nothing -> Just False
_ -> Just bool
alteration Nothing = case res of
Nothing -> Just False
_ -> Just True
_ -> id
g :: Zone -> Bool -> S.Set Zone -> S.Set Zone
g zone bool = case bool of
True -> S.insert zone
False -> id
dislodgingZones
:: M.Map Zone (Aligned Unit, SomeResolved OrderObject Typical)
-> Zone
-> S.Set Zone
dislodgingZones resolved zone = M.foldWithKey f S.empty resolved
where
f :: Zone
-> (Aligned Unit, SomeResolved OrderObject Typical)
-> S.Set Zone
-> S.Set Zone
f zone' (aunit, SomeResolved (object, res)) = case object of
MoveObject pt ->
if Zone pt == zone
then case (routes, res) of
([], Nothing) -> S.insert zone'
_ -> id
else id
where
routes = successfulConvoyRoutes (convoyRoutes resolved subject pt)
subject = (alignedThing aunit, zoneProvinceTarget zone')
_ -> id
candidateContinueSubjects :: GreatPower -> Occupation -> S.Set Subject
candidateContinueSubjects greatPower = S.fromList . allSubjects (Just greatPower)
candidateDisbandSubjects :: GreatPower -> Occupation -> S.Set Subject
candidateDisbandSubjects greatPower = S.fromList . allSubjects (Just greatPower)
candidateBuildSubjects :: GreatPower -> Occupation -> Control -> S.Set Subject
candidateBuildSubjects greatPower occupation control =
let candidateTargets = S.fromList $ candidateSupplyCentreTargets greatPower occupation control
units :: S.Set Unit
units = S.fromList $ [minBound..maxBound]
candidateSubjects :: S.Set Subject
candidateSubjects = setCartesianProduct units candidateTargets
in S.filter (\(u, pt) -> pt `S.member` unitCanOccupy u) candidateSubjects
candidateSupplyCentreTargets :: GreatPower -> Occupation -> Control -> [ProvinceTarget]
candidateSupplyCentreTargets greatPower occupation control = filter (not . (flip zoneOccupied) occupation . Zone) (controlledHomeSupplyCentreTargets greatPower control)
controlledHomeSupplyCentreTargets :: GreatPower -> Control -> [ProvinceTarget]
controlledHomeSupplyCentreTargets greatPower control = (controlledHomeSupplyCentres greatPower control >>= provinceTargets)
controlledHomeSupplyCentres :: GreatPower -> Control -> [Province]
controlledHomeSupplyCentres greatPower control = filter ((==) (Just greatPower) . (flip controller) control) (homeSupplyCentres greatPower)
homeSupplyCentres :: GreatPower -> [Province]
homeSupplyCentres greatPower = filter (isHome greatPower) supplyCentres
setCartesianProduct :: (Ord t, Ord s) => S.Set t -> S.Set s -> S.Set (t, s)
setCartesianProduct xs ys = S.foldr (\x -> S.union (S.map ((,) x) ys)) S.empty xs
powerSet :: Ord a => S.Set a -> S.Set (S.Set a)
powerSet = S.fold powerSetFold (S.singleton (S.empty))
where
powerSetFold :: Ord a => a -> S.Set (S.Set a) -> S.Set (S.Set a)
powerSetFold elem pset = S.union (S.map (S.insert elem) pset) pset
flattenSet :: Ord a => S.Set (S.Set a) -> S.Set a
flattenSet = S.foldr S.union S.empty
setComplement :: Ord a => S.Set a -> S.Set a -> S.Set a
setComplement relativeTo = S.filter (not . (flip S.member) relativeTo)
pickSet :: Ord a => Int -> S.Set (S.Set a) -> S.Set (S.Set a)
pickSet n sets
| n <= 0 = S.singleton S.empty
| otherwise = case S.size sets of
0 -> S.empty
m -> let xs = S.findMin sets
xss = S.delete xs sets
in case S.size xs of
0 -> pickSet n xss
l -> let rest = pickSet (n1) xss
in S.map (\(y, ys) -> S.insert y ys) (setCartesianProduct xs rest) `S.union` pickSet n xss
choose :: Ord a => Int -> S.Set a -> S.Set (S.Set a)
choose n set
| n <= 0 = S.singleton (S.empty)
| otherwise = case S.size set of
0 -> S.empty
m -> let x = S.findMin set
withoutX = choose n (S.delete x set)
withX = S.map (S.insert x) (choose (n1) (S.delete x set))
in withX `S.union` withoutX
newtype Intersection t = Intersection [t]
newtype Union t = Union [t]
evalIntersection
:: t
-> (t -> t -> t)
-> Intersection t
-> t
evalIntersection empty intersect (Intersection is) = foldr intersect empty is
evalUnion
:: t
-> (t -> t -> t)
-> Union t
-> t
evalUnion empty union (Union us) = foldr union empty us
class SuitableFunctor (f :: * -> *) where
type SuitableFunctorConstraint f :: * -> Constraint
suitableEmpty :: f t
suitableUnion :: SuitableFunctorConstraint f t => f t -> f t -> f t
suitableIntersect :: SuitableFunctorConstraint f t => f t -> f t -> f t
suitableMember :: SuitableFunctorConstraint f t => t -> f t -> Bool
suitableFmap
:: ( SuitableFunctorConstraint f t
, SuitableFunctorConstraint f s
)
=> (t -> s)
-> f t
-> f s
suitablePure :: SuitableFunctorConstraint f t => t -> f t
suitableBundle
:: ( SuitableFunctorConstraint f t
, SuitableFunctorConstraint f s
)
=> f t
-> f s
-> f (t, s)
suitableJoin :: SuitableFunctorConstraint f t => f (f t) -> f t
suitableBind
:: ( SuitableFunctorConstraint f t
, SuitableFunctorConstraint f (f s)
, SuitableFunctorConstraint f s
)
=> f t
-> (t -> f s)
-> f s
suitableBind x k = suitableJoin (suitableFmap k x)
instance SuitableFunctor [] where
type SuitableFunctorConstraint [] = Eq
suitableEmpty = []
suitableUnion = union
suitableIntersect = intersect
suitableMember = elem
suitableFmap = fmap
suitableBundle = cartesianProduct
where
cartesianProduct :: (Eq a, Eq b) => [a] -> [b] -> [(a, b)]
cartesianProduct xs ys = foldr (\x -> suitableUnion (fmap ((,) x) ys)) suitableEmpty xs
suitablePure = pure
suitableJoin = join
instance SuitableFunctor S.Set where
type SuitableFunctorConstraint S.Set = Ord
suitableEmpty = S.empty
suitableUnion = S.union
suitableIntersect = S.intersection
suitableMember = S.member
suitableFmap = S.map
suitableBundle = setCartesianProduct
suitablePure = S.singleton
suitableJoin = S.foldr suitableUnion suitableEmpty
data ValidityCharacterization (g :: * -> *) (f :: * -> *) (k :: [*]) where
VCNil
:: ( SuitableFunctor f
)
=> ValidityCharacterization g f '[]
VCCons
:: ( SuitableFunctor f
, SuitableFunctorConstraint f t
)
=> (ArgumentList Identity Identity ts -> TaggedIntersectionOfUnions g f t)
-> ValidityCharacterization g f ts
-> ValidityCharacterization g f (t ': ts)
validityCharacterizationTrans
:: (forall s . g s -> h s)
-> ValidityCharacterization g f ts
-> ValidityCharacterization h f ts
validityCharacterizationTrans natTrans vc = case vc of
VCNil -> VCNil
VCCons f rest -> VCCons (taggedIntersectionOfUnionsTrans natTrans . f) (validityCharacterizationTrans natTrans rest)
type TaggedIntersectionOfUnions (g :: * -> *) (f :: * -> *) (t :: *) = Intersection (g (Union (f t)))
taggedIntersectionOfUnionsTrans
:: (forall s . g s -> h s)
-> TaggedIntersectionOfUnions g f t
-> TaggedIntersectionOfUnions h f t
taggedIntersectionOfUnionsTrans trans iou = case iou of
Intersection is -> Intersection (fmap trans is)
evalTaggedIntersectionOfUnions
:: ( SuitableFunctor f
, SuitableFunctorConstraint f t
)
=> (forall s . g s -> s)
-> TaggedIntersectionOfUnions g f t
-> f t
evalTaggedIntersectionOfUnions exitG (Intersection is) =
case is of
[] -> suitableEmpty
[x] -> evalUnion suitableEmpty suitableUnion (exitG x)
x : xs -> suitableIntersect (evalUnion suitableEmpty suitableUnion (exitG x)) (evalTaggedIntersectionOfUnions exitG (Intersection xs))
checkTaggedIntersectionOfUnions
:: ( SuitableFunctor f
, SuitableFunctorConstraint f t
)
=> (forall s . g s -> s)
-> (forall s . g s -> r)
-> r
-> (r -> r -> r)
-> t
-> TaggedIntersectionOfUnions g f t
-> r
checkTaggedIntersectionOfUnions exitG inMonoid mempty mappend x (Intersection is) =
foldr (\xs b -> if suitableMember x (evalUnion suitableEmpty suitableUnion (exitG xs)) then b else mappend (inMonoid xs) b) mempty is
data ArgumentList (g :: * -> *) (f :: * -> *) (k :: [*]) where
ALNil :: ArgumentList g f '[]
ALCons :: g (f t) -> ArgumentList g f ts -> ArgumentList g f (t ': ts)
type family Every (c :: * -> Constraint) (ts :: [*]) :: Constraint where
Every c '[] = ()
Every c (t ': ts) = (c t, Every c ts)
instance Every Show ts => Show (ArgumentList Identity Identity ts) where
show al = case al of
ALNil -> "ALNil"
ALCons (Identity (Identity x)) rest -> "ALCons " ++ show x ++ " (" ++ show rest ++ ")"
instance Every Eq ts => Eq (ArgumentList Identity Identity ts) where
x == y = case (x, y) of
(ALNil, ALNil) -> True
(ALCons (Identity (Identity x')) xs, ALCons (Identity (Identity y')) ys) -> x' == y' && xs == ys
instance (Every Ord ts, Every Eq ts) => Ord (ArgumentList Identity Identity ts) where
x `compare` y = case (x, y) of
(ALNil, ALNil) -> EQ
(ALCons (Identity (Identity x')) xs, ALCons (Identity (Identity y')) ys) ->
case x' `compare` y' of
LT -> LT
GT -> GT
EQ -> xs `compare` ys
argListTrans
:: (forall s . g s -> h s)
-> ArgumentList g f ts
-> ArgumentList h f ts
argListTrans natTrans argList = case argList of
ALNil -> ALNil
ALCons x rest -> ALCons (natTrans x) (argListTrans natTrans rest)
argListTrans1
:: Functor g
=> (forall s . f s -> h s)
-> ArgumentList g f ts
-> ArgumentList g h ts
argListTrans1 natTrans argList = case argList of
ALNil -> ALNil
ALCons x rest -> ALCons (fmap natTrans x) (argListTrans1 natTrans rest)
evalValidityCharacterization
:: ( SuitableFunctor f
, ValidityCharacterizationConstraint f ts
)
=> ValidityCharacterization Identity f ts
-> f (ArgumentList Identity Identity ts)
evalValidityCharacterization vc = case vc of
VCNil -> suitablePure ALNil
VCCons next rest ->
let rest' = evalValidityCharacterization rest
in suitableBind rest' $ \xs ->
suitableBind (evalTaggedIntersectionOfUnions runIdentity (next xs)) $ \y ->
suitablePure (ALCons (Identity (Identity y)) xs)
type family ValidityCharacterizationConstraint (f :: * -> *) (ts :: [*]) :: Constraint where
ValidityCharacterizationConstraint f '[] = (
SuitableFunctorConstraint f (ArgumentList Identity Identity '[])
)
ValidityCharacterizationConstraint f (t ': ts) = (
SuitableFunctorConstraint f t
, SuitableFunctorConstraint f (f t)
, SuitableFunctorConstraint f (f (ArgumentList Identity Identity (t ': ts)))
, SuitableFunctorConstraint f (t, ArgumentList Identity Identity ts)
, SuitableFunctorConstraint f (ArgumentList Identity Identity (t ': ts))
, SuitableFunctorConstraint f (ArgumentList Identity Identity ts)
, ValidityCharacterizationConstraint f ts
)
type Constructor ts t = ArgumentList Identity Identity ts -> t
type Deconstructor ts t = t -> ArgumentList Identity Identity ts
type VOC g f ts t = (Constructor ts t, Deconstructor ts t, ValidityCharacterization g f ts)
synthesize
:: ( SuitableFunctor f
, SuitableFunctorConstraint f (ArgumentList Identity Identity ts)
, SuitableFunctorConstraint f t
, ValidityCharacterizationConstraint f ts
)
=> (forall s . g s -> Identity s)
-> VOC g f ts t
-> f t
synthesize trans (cons, _, vc) =
let fArgList = evalValidityCharacterization (validityCharacterizationTrans trans vc)
in suitableFmap cons fArgList
analyze
:: (forall s . g s -> s)
-> (forall s . g s -> r)
-> r
-> (r -> r -> r)
-> VOC g f ts t
-> t
-> r
analyze exitG inMonoid mempty mappend (_, uncons, vd) x =
let challenge = uncons x
in analyze' exitG inMonoid mempty mappend challenge vd
where
analyze'
:: (forall s . g s -> s)
-> (forall s . g s -> r)
-> r
-> (r -> r -> r)
-> ArgumentList Identity Identity ts
-> ValidityCharacterization g f ts
-> r
analyze' exitG inMonoid mempty mappend challenge vd = case (challenge, vd) of
(ALNil, VCNil) -> mempty
(ALCons (Identity (Identity x)) rest, VCCons f rest') ->
let possibilities = f rest
here = checkTaggedIntersectionOfUnions
exitG
inMonoid
mempty
mappend
x
possibilities
there = analyze' exitG inMonoid mempty mappend rest rest'
in here `mappend` there
type ValidityTag phase order = (,) (ValidityCriterion phase order)
type AdjustSetValidityTag = (,) (AdjustSetValidityCriterion)
moveVOC
:: GreatPower
-> Occupation
-> VOC (ValidityTag Typical Move) S.Set '[ProvinceTarget, Subject] (Order Typical Move)
moveVOC greatPower occupation = (cons, uncons, vc)
where
vc :: ValidityCharacterization (ValidityTag Typical Move) S.Set '[ProvinceTarget, Subject]
vc = VCCons (\(ALCons (Identity (Identity subject)) ALNil) -> Intersection [
(MoveUnitCanOccupy, Union [unitCanOccupy (subjectUnit subject)])
, (MoveReachable, Union [S.singleton (subjectProvinceTarget subject), validMoveAdjacency (Just occupation) subject])
])
. VCCons (\ALNil -> Intersection [(MoveValidSubject, Union [S.fromList (allSubjects (Just greatPower) occupation)])])
$ VCNil
cons :: ArgumentList Identity Identity '[ProvinceTarget, Subject] -> Order Typical Move
cons argList = case argList of
ALCons (Identity (Identity pt)) (ALCons (Identity (Identity subject)) ALNil) ->
Order (subject, MoveObject pt)
uncons :: Order Typical Move -> ArgumentList Identity Identity '[ProvinceTarget, Subject]
uncons (Order (subject, MoveObject pt)) =
ALCons (return (return pt)) (ALCons (return (return subject)) ALNil)
supportVOC
:: GreatPower
-> Occupation
-> VOC (ValidityTag Typical Support) S.Set '[Subject, ProvinceTarget, Subject] (Order Typical Support)
supportVOC greatPower occupation = (cons, uncons, vc)
where
vc :: ValidityCharacterization (ValidityTag Typical Support) S.Set '[Subject, ProvinceTarget, Subject]
vc =
VCCons (\(ALCons (Identity (Identity pt)) (ALCons (Identity (Identity subject1)) ALNil)) -> Intersection [
(SupportedCanDoMove, Union [S.filter (/= subject1) (validSupportSubjects occupation (subjectProvinceTarget subject1) pt)])
])
. VCCons (\(ALCons (Identity (Identity subject)) ALNil) -> Intersection [
(SupporterAdjacent, Union [validSupportTargets subject])
])
. VCCons (\ALNil -> Intersection [(SupportValidSubject, Union [S.fromList (allSubjects (Just greatPower) occupation)])])
$ VCNil
cons :: ArgumentList Identity Identity '[Subject, ProvinceTarget, Subject] -> Order Typical Support
cons argList = case argList of
ALCons (Identity (Identity subject2)) (ALCons (Identity (Identity pt)) (ALCons (Identity (Identity subject1)) ALNil)) ->
Order (subject1, SupportObject subject2 pt)
uncons :: Order Typical Support -> ArgumentList Identity Identity '[Subject, ProvinceTarget, Subject]
uncons order = case order of
Order (subject1, SupportObject subject2 pt) ->
ALCons (Identity (Identity subject2)) (ALCons (Identity (Identity pt)) (ALCons (Identity (Identity subject1)) ALNil))
convoyVOC
:: GreatPower
-> Occupation
-> VOC (ValidityTag Typical Convoy) S.Set '[ProvinceTarget, Subject, Subject] (Order Typical Convoy)
convoyVOC greatPower occupation = (cons, uncons, vc)
where
vc :: ValidityCharacterization (ValidityTag Typical Convoy) S.Set '[ProvinceTarget, Subject, Subject]
vc = VCCons (\(ALCons (Identity (Identity convoyed)) (ALCons (Identity (Identity convoyer)) ALNil)) -> Intersection [
(ConvoyValidConvoyTarget, Union [validConvoyTargets occupation convoyer convoyed])
])
. VCCons (\(ALCons (Identity (Identity subject)) ALNil) -> Intersection [
(ConvoyValidConvoySubject, Union [validConvoySubjects occupation])
])
. VCCons (\ALNil -> Intersection [
(ConvoyValidSubject, Union [validConvoyers (Just greatPower) occupation])
])
$ VCNil
cons :: ArgumentList Identity Identity '[ProvinceTarget, Subject, Subject] -> Order Typical Convoy
cons al = case al of
ALCons (Identity (Identity pt)) (ALCons (Identity (Identity convoyed)) (ALCons (Identity (Identity convoyer)) ALNil)) ->
Order (convoyer, ConvoyObject convoyed pt)
uncons :: Order Typical Convoy -> ArgumentList Identity Identity '[ProvinceTarget, Subject, Subject]
uncons order = case order of
Order (convoyer, ConvoyObject convoyed pt) ->
ALCons (Identity (Identity pt)) (ALCons (Identity (Identity convoyed)) (ALCons (Identity (Identity convoyer)) ALNil))
surrenderVOC
:: GreatPower
-> Dislodgement
-> VOC (ValidityTag Retreat Surrender) S.Set '[Subject] (Order Retreat Surrender)
surrenderVOC greatPower dislodgement = (cons, uncons, vc)
where
vc = VCCons (\ALNil -> Intersection [
(SurrenderValidSubject, Union [S.fromList (allSubjects (Just greatPower) dislodgement)])
])
$ VCNil
cons :: ArgumentList Identity Identity '[Subject] -> Order Retreat Surrender
cons al = case al of
ALCons (Identity (Identity subject)) ALNil ->
Order (subject, SurrenderObject)
uncons :: Order Retreat Surrender -> ArgumentList Identity Identity '[Subject]
uncons order = case order of
Order (subject, SurrenderObject) ->
ALCons (Identity (Identity subject)) ALNil
withdrawVOC
:: GreatPower
-> M.Map Zone (Aligned Unit, SomeResolved OrderObject Typical)
-> VOC (ValidityTag Retreat Withdraw) S.Set '[ProvinceTarget, Subject] (Order Retreat Withdraw)
withdrawVOC greatPower resolved = (cons, uncons, vc)
where
(dislodgement, occupation) = dislodgementAndOccupation resolved
vc = VCCons (\(ALCons (Identity (Identity subject)) ALNil) -> Intersection [
(WithdrawAdjacent, Union [validMoveTargets Nothing subject])
, (WithdrawNotDislodgingZone, Union [zoneSetToProvinceTargetSet $ S.difference setOfAllZones (dislodgingZones resolved (Zone (subjectProvinceTarget subject)))])
, (WithdrawUncontestedZone, Union [zoneSetToProvinceTargetSet $ S.difference setOfAllZones (contestedZones resolved)])
, (WithdrawUnoccupiedZone, Union [zoneSetToProvinceTargetSet $ S.difference setOfAllZones (occupiedZones occupation)])
])
. VCCons (\ALNil -> Intersection [
(WithdrawValidSubject, Union [S.fromList (allSubjects (Just greatPower) dislodgement)])
])
$ VCNil
cons :: ArgumentList Identity Identity '[ProvinceTarget, Subject] -> Order Retreat Withdraw
cons al = case al of
ALCons (Identity (Identity pt)) (ALCons (Identity (Identity subject)) ALNil) ->
Order (subject, WithdrawObject pt)
uncons :: Order Retreat Withdraw -> ArgumentList Identity Identity '[ProvinceTarget, Subject]
uncons order = case order of
Order (subject, WithdrawObject pt) ->
ALCons (Identity (Identity pt)) (ALCons (Identity (Identity subject)) ALNil)
continueSubjectVOC
:: GreatPower
-> Occupation
-> VOC (ValidityTag Adjust Continue) S.Set '[Subject] Subject
continueSubjectVOC greatPower occupation = (cons, uncons, vc)
where
vc :: ValidityCharacterization (ValidityTag Adjust Continue) S.Set '[Subject]
vc = VCCons (\ALNil -> Intersection [(ContinueValidSubject, Union [candidateContinueSubjects greatPower occupation])])
$ VCNil
cons :: ArgumentList Identity Identity '[Subject] -> Subject
cons al = case al of
ALCons (Identity (Identity subject)) ALNil -> subject
uncons :: Subject -> ArgumentList Identity Identity '[Subject]
uncons subject =
ALCons (Identity (Identity subject)) ALNil
disbandSubjectVOC
:: GreatPower
-> Occupation
-> VOC (ValidityTag Adjust Disband) S.Set '[Subject] Subject
disbandSubjectVOC greatPower occupation = (cons, uncons, vc)
where
vc :: ValidityCharacterization (ValidityTag Adjust Disband) S.Set '[Subject]
vc = VCCons (\ALNil -> Intersection [(DisbandValidSubject, Union [candidateDisbandSubjects greatPower occupation])])
$ VCNil
cons :: ArgumentList Identity Identity '[Subject] -> Subject
cons al = case al of
ALCons (Identity (Identity subject)) ALNil -> subject
uncons :: Subject -> ArgumentList Identity Identity '[Subject]
uncons subject =
ALCons (Identity (Identity subject)) ALNil
buildSubjectVOC
:: GreatPower
-> Occupation
-> Control
-> VOC (ValidityTag Adjust Build) S.Set '[Subject] Subject
buildSubjectVOC greatPower occupation control = (cons, uncons, vc)
where
vc :: ValidityCharacterization (ValidityTag Adjust Build) S.Set '[Subject]
vc = VCCons (\ALNil -> Intersection [(BuildValidSubject, Union [candidateBuildSubjects greatPower occupation control])])
$ VCNil
cons :: ArgumentList Identity Identity '[Subject] -> Subject
cons al = case al of
ALCons (Identity (Identity subject)) ALNil -> subject
uncons :: Subject -> ArgumentList Identity Identity '[Subject]
uncons subject =
ALCons (Identity (Identity subject)) ALNil
data AdjustSubjects = AdjustSubjects {
buildSubjects :: S.Set Subject
, disbandSubjects :: S.Set Subject
, continueSubjects :: S.Set Subject
}
deriving (Eq, Ord, Show)
adjustSubjectsVOC
:: GreatPower
-> Occupation
-> Control
-> AdjustSubjects
-> VOC AdjustSetValidityTag S.Set '[AdjustSubjects] AdjustSubjects
adjustSubjectsVOC greatPower occupation control subjects = (cons, uncons, vc)
where
deficit = supplyCentreDeficit greatPower occupation control
vc :: ValidityCharacterization AdjustSetValidityTag S.Set '[AdjustSubjects]
vc = VCCons (\ALNil -> tiu)
$ VCNil
cons :: ArgumentList Identity Identity '[AdjustSubjects] -> AdjustSubjects
cons al = case al of
ALCons (Identity (Identity x)) ALNil -> x
uncons :: AdjustSubjects -> ArgumentList Identity Identity '[AdjustSubjects]
uncons x =
ALCons (Identity (Identity x)) ALNil
tiu :: TaggedIntersectionOfUnions AdjustSetValidityTag S.Set AdjustSubjects
tiu | deficit > 0 = let disbandSets = choose deficit disbands
pairs = S.map (\xs -> (xs, continues `S.difference` xs)) disbandSets
valids :: S.Set AdjustSubjects
valids = S.map (\(disbands, continues) -> AdjustSubjects S.empty disbands continues) pairs
in Intersection [(RequiredNumberOfDisbands, Union (fmap S.singleton (S.toList valids)))]
| deficit < 0 = let buildSetsUnzoned :: [S.Set (S.Set Subject)]
buildSetsUnzoned = fmap (\n -> choose n builds) [0..(deficit)]
buildSets :: [S.Set (S.Set Subject)]
buildSets =
fmap
(S.map (S.map zonedSubjectSharp) . (S.map (S.map (ZonedSubjectSharp . zonedSubjectDull) . (S.map ZonedSubjectDull))))
buildSetsUnzoned
pairs :: [S.Set (S.Set Subject, S.Set Subject)]
pairs = (fmap . S.map) (\xs -> (xs, continues `S.difference` xs)) buildSets
valids :: [S.Set AdjustSubjects]
valids = (fmap . S.map) (\(builds, continues) -> AdjustSubjects builds S.empty continues) pairs
in Intersection [(AdmissibleNumberOfBuilds, Union valids)]
| otherwise = Intersection [(OnlyContinues, Union [S.singleton (AdjustSubjects S.empty S.empty continues)])]
builds = buildSubjects subjects
disbands = disbandSubjects subjects
continues = continueSubjects subjects