{-
	Copyright (C) 2018 Dr. Alistair Ward

	This file is part of BishBosh.

	BishBosh is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	BishBosh is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with BishBosh.  If not, see <http://www.gnu.org/licenses/>.
-}
{- |
 [@AUTHOR@]	Dr. Alistair Ward

 [@DESCRIPTION@]

	* A view of the /board/ from the perspective of its /piece/s.

	* cf. the square-centric model of the board defined in "BishBosh.State.MaybePieceByCoordinates".
-}

module BishBosh.State.CoordinatesByRankByLogicalColour(
-- * Types
-- ** Type-synonyms
--	CoordinatesByRank,
	CoordinatesByLogicalColour,
--	Transformation,
-- ** Data-types
	CoordinatesByRankByLogicalColour(
--		MkCoordinatesByRankByLogicalColour,
		deconstruct
	),
-- * Functions
	findPassedPawnCoordinatesByLogicalColour,
	findPiecesOfColour,
	assocs,
	listCoordinates,
-- ** Accessors
	getKingsCoordinates,
	dereference,
-- ** Constructor
	fromMaybePieceByCoordinates,
-- ** Mutators
--	deleteCoordinates,
	movePiece,
	sortCoordinates
) where

import			Control.Arrow((&&&), (|||))
import			Data.Array.IArray((!), (//))
import qualified	BishBosh.Attribute.Direction				as Attribute.Direction
import qualified	BishBosh.Attribute.LogicalColour			as Attribute.LogicalColour
import qualified	BishBosh.Attribute.Rank					as Attribute.Rank
import qualified	BishBosh.Cartesian.Abscissa				as Cartesian.Abscissa
import qualified	BishBosh.Cartesian.Coordinates				as Cartesian.Coordinates
import qualified	BishBosh.Cartesian.Vector				as Cartesian.Vector
import qualified	BishBosh.Component.Accountant				as Component.Accountant
import qualified	BishBosh.Component.Move					as Component.Move
import qualified	BishBosh.Component.Piece				as Component.Piece
import qualified	BishBosh.Component.PieceSquareByCoordinatesByRank	as Component.PieceSquareByCoordinatesByRank
import qualified	BishBosh.Component.Zobrist				as Component.Zobrist
import qualified	BishBosh.Property.Empty					as Property.Empty
import qualified	BishBosh.Property.FixedMembership			as Property.FixedMembership
import qualified	BishBosh.Property.Opposable				as Property.Opposable
import qualified	BishBosh.State.MaybePieceByCoordinates			as State.MaybePieceByCoordinates
import qualified	BishBosh.StateProperty.Censor				as StateProperty.Censor
import qualified	BishBosh.StateProperty.Hashable				as StateProperty.Hashable
import qualified	BishBosh.StateProperty.Seeker				as StateProperty.Seeker
import qualified	Control.Arrow
import qualified	Control.DeepSeq
import qualified	Control.Exception
import qualified	Data.Array.IArray
import qualified	Data.Foldable
import qualified	Data.List
import qualified	Data.Map.Strict						as Map
import qualified	Data.Maybe

-- | The /coordinate/s of all the pieces of one /rank/.
type CoordinatesByRank	= Attribute.Rank.ArrayByRank [Cartesian.Coordinates.Coordinates]

{- |
	* This structure allows one to determine the set of /coordinates/ where a type of /piece/ is located.

	* CAVEAT: the list of /coordinates/ is unordered, so test for equality using @ deconstruct . sortCoordinates @.
-}
newtype CoordinatesByRankByLogicalColour	= MkCoordinatesByRankByLogicalColour {
	CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct	:: Attribute.LogicalColour.ArrayByLogicalColour CoordinatesByRank
}

instance Control.DeepSeq.NFData CoordinatesByRankByLogicalColour where
	rnf :: CoordinatesByRankByLogicalColour -> ()
rnf MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= ArrayByLogicalColour CoordinatesByRank -> ()
forall a. NFData a => a -> ()
Control.DeepSeq.rnf ArrayByLogicalColour CoordinatesByRank
byLogicalColour

instance StateProperty.Censor.Censor CoordinatesByRankByLogicalColour where
	countPiecesByLogicalColour :: CoordinatesByRankByLogicalColour -> (NPieces, NPieces)
countPiecesByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= ((LogicalColour -> NPieces) -> LogicalColour -> NPieces
forall a b. (a -> b) -> a -> b
$ LogicalColour
Attribute.LogicalColour.Black) ((LogicalColour -> NPieces) -> NPieces)
-> ((LogicalColour -> NPieces) -> NPieces)
-> (LogicalColour -> NPieces)
-> (NPieces, NPieces)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& ((LogicalColour -> NPieces) -> LogicalColour -> NPieces
forall a b. (a -> b) -> a -> b
$ LogicalColour
Attribute.LogicalColour.White) ((LogicalColour -> NPieces) -> (NPieces, NPieces))
-> (LogicalColour -> NPieces) -> (NPieces, NPieces)
forall a b. (a -> b) -> a -> b
$ (NPieces -> [Coordinates] -> NPieces)
-> NPieces -> CoordinatesByRank -> NPieces
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Data.List.foldl' (\NPieces
acc -> (NPieces -> NPieces -> NPieces
forall a. Num a => a -> a -> a
+ NPieces
acc) (NPieces -> NPieces)
-> ([Coordinates] -> NPieces) -> [Coordinates] -> NPieces
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NPieces -> NPieces
forall a b. (Integral a, Num b) => a -> b
fromIntegral (NPieces -> NPieces)
-> ([Coordinates] -> NPieces) -> [Coordinates] -> NPieces
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Coordinates] -> NPieces
forall (t :: * -> *) a. Foldable t => t a -> NPieces
length) NPieces
0 (CoordinatesByRank -> NPieces)
-> (LogicalColour -> CoordinatesByRank) -> LogicalColour -> NPieces
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> LogicalColour -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!)

	countPieces :: CoordinatesByRankByLogicalColour -> NPieces
countPieces MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= (NPieces -> CoordinatesByRank -> NPieces)
-> NPieces -> ArrayByLogicalColour CoordinatesByRank -> NPieces
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Data.Foldable.foldl' (
		(NPieces -> [Coordinates] -> NPieces)
-> NPieces -> CoordinatesByRank -> NPieces
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Data.List.foldl' ((NPieces -> [Coordinates] -> NPieces)
 -> NPieces -> CoordinatesByRank -> NPieces)
-> (NPieces -> [Coordinates] -> NPieces)
-> NPieces
-> CoordinatesByRank
-> NPieces
forall a b. (a -> b) -> a -> b
$ \NPieces
acc -> (NPieces -> NPieces -> NPieces
forall a. Num a => a -> a -> a
+ NPieces
acc) (NPieces -> NPieces)
-> ([Coordinates] -> NPieces) -> [Coordinates] -> NPieces
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NPieces -> NPieces
forall a b. (Integral a, Num b) => a -> b
fromIntegral (NPieces -> NPieces)
-> ([Coordinates] -> NPieces) -> [Coordinates] -> NPieces
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Coordinates] -> NPieces
forall (t :: * -> *) a. Foldable t => t a -> NPieces
length
	 ) NPieces
0 ArrayByLogicalColour CoordinatesByRank
byLogicalColour

	countPieceDifferenceByRank :: CoordinatesByRankByLogicalColour -> NPiecesByRank
countPieceDifferenceByRank MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= [NPieces] -> NPiecesByRank
forall (a :: * -> * -> *) e. IArray a e => [e] -> a Rank e
Attribute.Rank.listArrayByRank ([NPieces] -> NPiecesByRank)
-> ((LogicalColour -> [NPieces]) -> [NPieces])
-> (LogicalColour -> [NPieces])
-> NPiecesByRank
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([NPieces] -> [NPieces] -> [NPieces])
-> ([NPieces], [NPieces]) -> [NPieces]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (
		(NPieces -> NPieces -> NPieces)
-> [NPieces] -> [NPieces] -> [NPieces]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-)
	 ) (([NPieces], [NPieces]) -> [NPieces])
-> ((LogicalColour -> [NPieces]) -> ([NPieces], [NPieces]))
-> (LogicalColour -> [NPieces])
-> [NPieces]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
		((LogicalColour -> [NPieces]) -> LogicalColour -> [NPieces]
forall a b. (a -> b) -> a -> b
$ LogicalColour
Attribute.LogicalColour.White) ((LogicalColour -> [NPieces]) -> [NPieces])
-> ((LogicalColour -> [NPieces]) -> [NPieces])
-> (LogicalColour -> [NPieces])
-> ([NPieces], [NPieces])
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& ((LogicalColour -> [NPieces]) -> LogicalColour -> [NPieces]
forall a b. (a -> b) -> a -> b
$ LogicalColour
Attribute.LogicalColour.Black)
	 ) ((LogicalColour -> [NPieces]) -> NPiecesByRank)
-> (LogicalColour -> [NPieces]) -> NPiecesByRank
forall a b. (a -> b) -> a -> b
$ ([Coordinates] -> NPieces) -> [[Coordinates]] -> [NPieces]
forall a b. (a -> b) -> [a] -> [b]
map (NPieces -> NPieces
forall a b. (Integral a, Num b) => a -> b
fromIntegral (NPieces -> NPieces)
-> ([Coordinates] -> NPieces) -> [Coordinates] -> NPieces
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Coordinates] -> NPieces
forall (t :: * -> *) a. Foldable t => t a -> NPieces
length) ([[Coordinates]] -> [NPieces])
-> (LogicalColour -> [[Coordinates]]) -> LogicalColour -> [NPieces]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CoordinatesByRank -> [[Coordinates]]
forall (t :: * -> *) a. Foldable t => t a -> [a]
Data.Foldable.toList (CoordinatesByRank -> [[Coordinates]])
-> (LogicalColour -> CoordinatesByRank)
-> LogicalColour
-> [[Coordinates]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> LogicalColour -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!)

	hasInsufficientMaterial :: CoordinatesByRankByLogicalColour -> Bool
hasInsufficientMaterial MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= (CoordinatesByRank -> Bool)
-> ArrayByLogicalColour CoordinatesByRank -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
Data.Foldable.all (
		\CoordinatesByRank
byRank -> (Rank -> Bool) -> [Rank] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (
			[Coordinates] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Coordinates] -> Bool) -> (Rank -> [Coordinates]) -> Rank -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CoordinatesByRank
byRank CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!)
		) [Rank]
Attribute.Rank.individuallySufficientMaterial
	 ) ArrayByLogicalColour CoordinatesByRank
byLogicalColour Bool -> Bool -> Bool
&& case [Coordinates]
blackKnights [Coordinates] -> [Coordinates] -> [Coordinates]
forall a. [a] -> [a] -> [a]
++ [Coordinates]
whiteKnights of
		[]	-> [Coordinates] -> Bool
Cartesian.Coordinates.areSquaresIsochromatic [Coordinates]
bishops
		[Coordinates
_]	-> [Coordinates] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Coordinates]
bishops
		[Coordinates]
_	-> Bool
False
		where
			[[Coordinates]
blackKnights, [Coordinates]
blackBishops, [Coordinates]
whiteKnights, [Coordinates]
whiteBishops]	= [
				CoordinatesByRank
byRank CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
rank |
					CoordinatesByRank
byRank	<- ArrayByLogicalColour CoordinatesByRank -> [CoordinatesByRank]
forall (t :: * -> *) a. Foldable t => t a -> [a]
Data.Foldable.toList ArrayByLogicalColour CoordinatesByRank
byLogicalColour,
					Rank
rank	<- [Rank
Attribute.Rank.Knight, Rank
Attribute.Rank.Bishop]
			 ] -- List-comprehension.

			bishops :: [Coordinates]
bishops	= [Coordinates]
blackBishops [Coordinates] -> [Coordinates] -> [Coordinates]
forall a. [a] -> [a] -> [a]
++ [Coordinates]
whiteBishops

	hasBothKings :: CoordinatesByRankByLogicalColour -> Bool
hasBothKings MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ (CoordinatesByRank -> Bool)
-> ArrayByLogicalColour CoordinatesByRank -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
Data.Foldable.any ([Coordinates] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Coordinates] -> Bool)
-> (CoordinatesByRank -> [Coordinates])
-> CoordinatesByRank
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
Attribute.Rank.King)) ArrayByLogicalColour CoordinatesByRank
byLogicalColour	-- CAVEAT: true for more than one King per side also.

instance StateProperty.Hashable.Hashable CoordinatesByRankByLogicalColour where
	listRandoms :: CoordinatesByRankByLogicalColour
-> Zobrist positionHash -> [positionHash]
listRandoms MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour } Zobrist positionHash
zobrist	= [
		Index -> Zobrist positionHash -> positionHash
forall positionHash. Index -> Zobrist positionHash -> positionHash
Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (LogicalColour
logicalColour, Rank
rank, Coordinates
coordinates) Zobrist positionHash
zobrist |
			(LogicalColour
logicalColour, CoordinatesByRank
byRank)	<- ArrayByLogicalColour CoordinatesByRank
-> [(LogicalColour, CoordinatesByRank)]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
Data.Array.IArray.assocs ArrayByLogicalColour CoordinatesByRank
byLogicalColour,
			(Rank
rank, [Coordinates]
coordinatesList)	<- CoordinatesByRank -> [(Rank, [Coordinates])]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
Data.Array.IArray.assocs CoordinatesByRank
byRank,
			Coordinates
coordinates		<- [Coordinates]
coordinatesList
	 ] -- List-comprehension.

{- |
	* Find any @Knight@s of the specified /logical colour/, in attack-range around the specified /coordinates/.

	* CAVEAT: nothing is said about whether any /piece/ at the specified /coordinates/ belongs to the opponent, as one might expect.
-}
instance StateProperty.Seeker.Seeker CoordinatesByRankByLogicalColour {-CAVEAT: MultiParamTypeClasses-} where
	findProximateKnights :: LogicalColour
-> Coordinates -> CoordinatesByRankByLogicalColour -> [Coordinates]
findProximateKnights LogicalColour
logicalColour Coordinates
destination MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= (Coordinates -> Bool) -> [Coordinates] -> [Coordinates]
forall a. (a -> Bool) -> [a] -> [a]
filter (
		\Coordinates
source -> Coordinates
source Coordinates -> Coordinates -> Bool
forall a. Eq a => a -> a -> Bool
/= Coordinates
destination {-guard against attempting to constructing a null vector-} Bool -> Bool -> Bool
&& Vector -> Bool
Cartesian.Vector.isKnightsMove (
			Coordinates -> Coordinates -> Vector
Cartesian.Vector.measureDistance Coordinates
source Coordinates
destination
		)
	 ) ([Coordinates] -> [Coordinates]) -> [Coordinates] -> [Coordinates]
forall a b. (a -> b) -> a -> b
$ ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> LogicalColour -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! LogicalColour
logicalColour CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
Attribute.Rank.Knight

	findPieces :: (Piece -> Bool)
-> CoordinatesByRankByLogicalColour -> [LocatedPiece]
findPieces Piece -> Bool
predicate MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= [
		(Coordinates
coordinates, Piece
piece) |
			(LogicalColour
logicalColour, CoordinatesByRank
byRank)	<- ArrayByLogicalColour CoordinatesByRank
-> [(LogicalColour, CoordinatesByRank)]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
Data.Array.IArray.assocs ArrayByLogicalColour CoordinatesByRank
byLogicalColour,
			(Rank
rank, [Coordinates]
coordinatesList)	<- CoordinatesByRank -> [(Rank, [Coordinates])]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
Data.Array.IArray.assocs CoordinatesByRank
byRank,
			let piece :: Piece
piece	= LogicalColour -> Rank -> Piece
Component.Piece.mkPiece LogicalColour
logicalColour Rank
rank,
			Piece -> Bool
predicate Piece
piece,
			Coordinates
coordinates		<- [Coordinates]
coordinatesList
	 ] -- List-comprehension.

	countPawnsByFileByLogicalColour :: CoordinatesByRankByLogicalColour -> NPiecesByFileByLogicalColour
countPawnsByFileByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= (CoordinatesByRank -> NPiecesByFile)
-> ArrayByLogicalColour CoordinatesByRank
-> NPiecesByFileByLogicalColour
forall (a :: * -> * -> *) e' e i.
(IArray a e', IArray a e, Ix i) =>
(e' -> e) -> a i e' -> a i e
Data.Array.IArray.amap (
		(NPiecesByFile -> Coordinates -> NPiecesByFile)
-> NPiecesByFile -> [Coordinates] -> NPiecesByFile
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Data.List.foldl' (
			\NPiecesByFile
m Coordinates
coordinates -> NPieces -> NPiecesByFile -> NPiecesByFile
StateProperty.Seeker.accumulatePawnsByFile (Coordinates -> NPieces
Cartesian.Coordinates.getX Coordinates
coordinates) NPiecesByFile
m
		) NPiecesByFile
forall a. Empty a => a
Property.Empty.empty ([Coordinates] -> NPiecesByFile)
-> (CoordinatesByRank -> [Coordinates])
-> CoordinatesByRank
-> NPiecesByFile
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
Attribute.Rank.Pawn)
	 ) ArrayByLogicalColour CoordinatesByRank
byLogicalColour

instance Component.Accountant.Accountant CoordinatesByRankByLogicalColour where
	sumPieceSquareValueByLogicalColour :: PieceSquareByCoordinatesByRank pieceSquareValue
-> NPieces
-> CoordinatesByRankByLogicalColour
-> [pieceSquareValue]
sumPieceSquareValueByLogicalColour PieceSquareByCoordinatesByRank pieceSquareValue
pieceSquareByCoordinatesByRank NPieces
nPieces MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= ((LogicalColour, CoordinatesByRank) -> pieceSquareValue)
-> [(LogicalColour, CoordinatesByRank)] -> [pieceSquareValue]
forall a b. (a -> b) -> [a] -> [b]
map (
		\(LogicalColour
logicalColour, CoordinatesByRank
byRank) -> (pieceSquareValue -> (Rank, [Coordinates]) -> pieceSquareValue)
-> pieceSquareValue -> [(Rank, [Coordinates])] -> pieceSquareValue
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Data.List.foldl' (
			\pieceSquareValue
acc (Rank
rank, [Coordinates]
coordinatesList) -> (pieceSquareValue -> Coordinates -> pieceSquareValue)
-> pieceSquareValue -> [Coordinates] -> pieceSquareValue
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Data.List.foldl' (
				\pieceSquareValue
acc' -> (pieceSquareValue -> pieceSquareValue -> pieceSquareValue
forall a. Num a => a -> a -> a
+ pieceSquareValue
acc') (pieceSquareValue -> pieceSquareValue)
-> (Coordinates -> pieceSquareValue)
-> Coordinates
-> pieceSquareValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PieceSquareByCoordinatesByRank pieceSquareValue
-> NPieces
-> LogicalColour
-> Rank
-> Coordinates
-> pieceSquareValue
forall pieceSquareValue.
PieceSquareByCoordinatesByRank pieceSquareValue
-> NPieces
-> LogicalColour
-> Rank
-> Coordinates
-> pieceSquareValue
Component.PieceSquareByCoordinatesByRank.findPieceSquareValue PieceSquareByCoordinatesByRank pieceSquareValue
pieceSquareByCoordinatesByRank NPieces
nPieces LogicalColour
logicalColour Rank
rank
			) pieceSquareValue
acc [Coordinates]
coordinatesList
		) pieceSquareValue
0 ([(Rank, [Coordinates])] -> pieceSquareValue)
-> [(Rank, [Coordinates])] -> pieceSquareValue
forall a b. (a -> b) -> a -> b
$ CoordinatesByRank -> [(Rank, [Coordinates])]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
Data.Array.IArray.assocs CoordinatesByRank
byRank
	 ) ([(LogicalColour, CoordinatesByRank)] -> [pieceSquareValue])
-> [(LogicalColour, CoordinatesByRank)] -> [pieceSquareValue]
forall a b. (a -> b) -> a -> b
$ ArrayByLogicalColour CoordinatesByRank
-> [(LogicalColour, CoordinatesByRank)]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
Data.Array.IArray.assocs ArrayByLogicalColour CoordinatesByRank
byLogicalColour

-- | Constructor.
fromMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates -> CoordinatesByRankByLogicalColour
fromMaybePieceByCoordinates :: MaybePieceByCoordinates -> CoordinatesByRankByLogicalColour
fromMaybePieceByCoordinates MaybePieceByCoordinates
maybePieceByCoordinates	= ArrayByLogicalColour CoordinatesByRank
-> CoordinatesByRankByLogicalColour
MkCoordinatesByRankByLogicalColour (ArrayByLogicalColour CoordinatesByRank
 -> CoordinatesByRankByLogicalColour)
-> (([(Piece, [Coordinates])], [(Piece, [Coordinates])])
    -> ArrayByLogicalColour CoordinatesByRank)
-> ([(Piece, [Coordinates])], [(Piece, [Coordinates])])
-> CoordinatesByRankByLogicalColour
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
	\([(Piece, [Coordinates])]
b, [(Piece, [Coordinates])]
w) -> [CoordinatesByRank] -> ArrayByLogicalColour CoordinatesByRank
forall (a :: * -> * -> *) e. IArray a e => [e] -> a LogicalColour e
Attribute.LogicalColour.listArrayByLogicalColour ([CoordinatesByRank] -> ArrayByLogicalColour CoordinatesByRank)
-> [CoordinatesByRank] -> ArrayByLogicalColour CoordinatesByRank
forall a b. (a -> b) -> a -> b
$ ([(Piece, [Coordinates])] -> CoordinatesByRank)
-> [[(Piece, [Coordinates])]] -> [CoordinatesByRank]
forall a b. (a -> b) -> [a] -> [b]
map (
		([Coordinates] -> [Coordinates] -> [Coordinates])
-> [Coordinates]
-> (Rank, Rank)
-> [(Rank, [Coordinates])]
-> CoordinatesByRank
forall (a :: * -> * -> *) e i e'.
(IArray a e, Ix i) =>
(e -> e' -> e) -> e -> (i, i) -> [(i, e')] -> a i e
Data.Array.IArray.accumArray [Coordinates] -> [Coordinates] -> [Coordinates]
forall a. [a] -> [a] -> [a]
(++) [] (Rank
forall a. Bounded a => a
minBound, Rank
forall a. Bounded a => a
maxBound) ([(Rank, [Coordinates])] -> CoordinatesByRank)
-> ([(Piece, [Coordinates])] -> [(Rank, [Coordinates])])
-> [(Piece, [Coordinates])]
-> CoordinatesByRank
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Piece, [Coordinates]) -> (Rank, [Coordinates]))
-> [(Piece, [Coordinates])] -> [(Rank, [Coordinates])]
forall a b. (a -> b) -> [a] -> [b]
map ((Piece -> Rank) -> (Piece, [Coordinates]) -> (Rank, [Coordinates])
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
Control.Arrow.first Piece -> Rank
Component.Piece.getRank)
	) [[(Piece, [Coordinates])]
b, [(Piece, [Coordinates])]
w]
 ) (([(Piece, [Coordinates])], [(Piece, [Coordinates])])
 -> CoordinatesByRankByLogicalColour)
-> ([(Piece, [Coordinates])], [(Piece, [Coordinates])])
-> CoordinatesByRankByLogicalColour
forall a b. (a -> b) -> a -> b
$ ((Piece, [Coordinates]) -> Bool)
-> [(Piece, [Coordinates])]
-> ([(Piece, [Coordinates])], [(Piece, [Coordinates])])
forall a. (a -> Bool) -> [a] -> ([a], [a])
Data.List.partition (
	Piece -> Bool
Component.Piece.isBlack (Piece -> Bool)
-> ((Piece, [Coordinates]) -> Piece)
-> (Piece, [Coordinates])
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Piece, [Coordinates]) -> Piece
forall a b. (a, b) -> a
fst {-piece-}
 ) [
	(Piece
piece, [Coordinates
coordinates]) |
		(Coordinates
coordinates, Piece
piece)	<- MaybePieceByCoordinates -> [LocatedPiece]
forall seeker. Seeker seeker => seeker -> [LocatedPiece]
StateProperty.Seeker.findAllPieces MaybePieceByCoordinates
maybePieceByCoordinates
 ] -- List-comprehension.

-- | Dereference the array.
dereference
	:: Attribute.LogicalColour.LogicalColour
	-> Attribute.Rank.Rank
	-> CoordinatesByRankByLogicalColour
	-> [Cartesian.Coordinates.Coordinates]
{-# INLINE dereference #-}
dereference :: LogicalColour
-> Rank -> CoordinatesByRankByLogicalColour -> [Coordinates]
dereference LogicalColour
logicalColour Rank
rank MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> LogicalColour -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! LogicalColour
logicalColour CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
rank

-- | Build an association-list.
assocs :: CoordinatesByRankByLogicalColour -> [(Component.Piece.Piece, [Cartesian.Coordinates.Coordinates])]
assocs :: CoordinatesByRankByLogicalColour -> [(Piece, [Coordinates])]
assocs MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= [
	(LogicalColour -> Rank -> Piece
Component.Piece.mkPiece LogicalColour
logicalColour Rank
rank, [Coordinates]
coordinatesList) |
		(LogicalColour
logicalColour, CoordinatesByRank
byRank)	<- ArrayByLogicalColour CoordinatesByRank
-> [(LogicalColour, CoordinatesByRank)]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
Data.Array.IArray.assocs ArrayByLogicalColour CoordinatesByRank
byLogicalColour,
		(Rank
rank, [Coordinates]
coordinatesList)	<- CoordinatesByRank -> [(Rank, [Coordinates])]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
Data.Array.IArray.assocs CoordinatesByRank
byRank
 ] -- List-comprehension.

-- | Access the coordinate-lists.
listCoordinates :: CoordinatesByRankByLogicalColour -> [Cartesian.Coordinates.Coordinates]
listCoordinates :: CoordinatesByRankByLogicalColour -> [Coordinates]
listCoordinates MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= [
	Coordinates
coordinates |
		CoordinatesByRank
byRank		<- ArrayByLogicalColour CoordinatesByRank -> [CoordinatesByRank]
forall (t :: * -> *) a. Foldable t => t a -> [a]
Data.Foldable.toList ArrayByLogicalColour CoordinatesByRank
byLogicalColour,
		[Coordinates]
coordinatesList	<- CoordinatesByRank -> [[Coordinates]]
forall (t :: * -> *) a. Foldable t => t a -> [a]
Data.Foldable.toList CoordinatesByRank
byRank,
		Coordinates
coordinates	<- [Coordinates]
coordinatesList
 ] -- List-comprehension.

-- | Get the /coordinates/ of the @King@ of the specified /logical colour/.
getKingsCoordinates
	:: Attribute.LogicalColour.LogicalColour	-- ^ The /logical colour/ of the @King@ to find.
	-> CoordinatesByRankByLogicalColour
	-> Cartesian.Coordinates.Coordinates
{-# INLINE getKingsCoordinates #-}
getKingsCoordinates :: LogicalColour -> CoordinatesByRankByLogicalColour -> Coordinates
getKingsCoordinates LogicalColour
logicalColour MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= Bool -> Coordinates -> Coordinates
forall a. (?callStack::CallStack) => Bool -> a -> a
Control.Exception.assert (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [Coordinates] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Coordinates]
coordinates) (Coordinates -> Coordinates) -> Coordinates -> Coordinates
forall a b. (a -> b) -> a -> b
$ [Coordinates] -> Coordinates
forall a. [a] -> a
head [Coordinates]
coordinates {-there should be exactly one-} where
	coordinates :: [Coordinates]
coordinates	= ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> LogicalColour -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! LogicalColour
logicalColour CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
Attribute.Rank.King

-- | Locate all /piece/s of the specified /logical colour/.
findPiecesOfColour
	:: Attribute.LogicalColour.LogicalColour	-- ^ The /logical colour/ of the /piece/s to find.
	-> CoordinatesByRankByLogicalColour
	-> [Component.Piece.LocatedPiece]
findPiecesOfColour :: LogicalColour -> CoordinatesByRankByLogicalColour -> [LocatedPiece]
findPiecesOfColour LogicalColour
logicalColour MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= [
	(Coordinates
coordinates, LogicalColour -> Rank -> Piece
Component.Piece.mkPiece LogicalColour
logicalColour Rank
rank) |
		(Rank
rank, [Coordinates]
coordinatesList)	<- CoordinatesByRank -> [(Rank, [Coordinates])]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
Data.Array.IArray.assocs (CoordinatesByRank -> [(Rank, [Coordinates])])
-> CoordinatesByRank -> [(Rank, [Coordinates])]
forall a b. (a -> b) -> a -> b
$ ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> LogicalColour -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! LogicalColour
logicalColour,
		Coordinates
coordinates		<- [Coordinates]
coordinatesList
 ] -- List-comprehension.

-- | A list of /coordinates/ for each /logical colour/.
type CoordinatesByLogicalColour	= Attribute.LogicalColour.ArrayByLogicalColour [Cartesian.Coordinates.Coordinates]

-- | For each /logical colour/, find the /coordinates/ of any passed @Pawn@s (<https://en.wikipedia.org/wiki/Passed_pawn>).
findPassedPawnCoordinatesByLogicalColour :: CoordinatesByRankByLogicalColour -> CoordinatesByLogicalColour
findPassedPawnCoordinatesByLogicalColour :: CoordinatesByRankByLogicalColour -> CoordinatesByLogicalColour
findPassedPawnCoordinatesByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= [[Coordinates]] -> CoordinatesByLogicalColour
forall (a :: * -> * -> *) e. IArray a e => [e] -> a LogicalColour e
Attribute.LogicalColour.listArrayByLogicalColour ([[Coordinates]] -> CoordinatesByLogicalColour)
-> [[Coordinates]] -> CoordinatesByLogicalColour
forall a b. (a -> b) -> a -> b
$ (LogicalColour -> [Coordinates])
-> [LogicalColour] -> [[Coordinates]]
forall a b. (a -> b) -> [a] -> [b]
map (
	\LogicalColour
logicalColour	-> let
		opponentsLogicalColour :: LogicalColour
opponentsLogicalColour	= LogicalColour -> LogicalColour
forall a. Opposable a => a -> a
Property.Opposable.getOpposite LogicalColour
logicalColour
		opposingPawnYByX :: NPiecesByFile
opposingPawnYByX	= (NPiecesByFile -> Coordinates -> NPiecesByFile)
-> NPiecesByFile -> [Coordinates] -> NPiecesByFile
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Data.List.foldl' (
			\NPiecesByFile
m Coordinates
coordinates -> (NPieces -> NPieces -> NPiecesByFile -> NPiecesByFile)
-> (NPieces, NPieces) -> NPiecesByFile -> NPiecesByFile
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (
				(NPieces -> NPieces -> NPieces)
-> NPieces -> NPieces -> NPiecesByFile -> NPiecesByFile
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith ((NPieces -> NPieces -> NPieces)
 -> NPieces -> NPieces -> NPiecesByFile -> NPiecesByFile)
-> (NPieces -> NPieces -> NPieces)
-> NPieces
-> NPieces
-> NPiecesByFile
-> NPiecesByFile
forall a b. (a -> b) -> a -> b
$ if LogicalColour -> Bool
Attribute.LogicalColour.isBlack LogicalColour
opponentsLogicalColour
					then NPieces -> NPieces -> NPieces
forall a. Ord a => a -> a -> a
max
					else NPieces -> NPieces -> NPieces
forall a. Ord a => a -> a -> a
min
			) {-only compare with the least advanced opposing Pawn in each file-} (
				Coordinates -> NPieces
Cartesian.Coordinates.getX (Coordinates -> NPieces)
-> (Coordinates -> NPieces) -> Coordinates -> (NPieces, NPieces)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& Coordinates -> NPieces
Cartesian.Coordinates.getY (Coordinates -> (NPieces, NPieces))
-> Coordinates -> (NPieces, NPieces)
forall a b. (a -> b) -> a -> b
$ Coordinates
coordinates
			) NPiecesByFile
m
		 ) NPiecesByFile
forall a. Empty a => a
Property.Empty.empty ([Coordinates] -> NPiecesByFile) -> [Coordinates] -> NPiecesByFile
forall a b. (a -> b) -> a -> b
$ LogicalColour -> [Coordinates]
findPawns LogicalColour
opponentsLogicalColour
	in (Coordinates -> Bool) -> [Coordinates] -> [Coordinates]
forall a. (a -> Bool) -> [a] -> [a]
filter (
		\Coordinates
coordinates -> (NPieces -> Bool) -> [NPieces] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (
			Bool -> (NPieces -> Bool) -> Maybe NPieces -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
Data.Maybe.maybe Bool
True {-absence of opposition doesn't impede advance-} (
				(
					Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
/= LogicalColour -> Ordering
Attribute.Direction.advanceDirection LogicalColour
logicalColour	-- Either equal or backwards is OK.
				) (Ordering -> Bool) -> (NPieces -> Ordering) -> NPieces -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
					{-opponent-} NPieces -> NPieces -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` Coordinates -> NPieces
Cartesian.Coordinates.getY Coordinates
coordinates
				) -- As a Pawn advances, it becomes "Passed" when the y-distance to the least advanced adjacent opposing Pawn, is either equal or backwards.
			 ) (Maybe NPieces -> Bool)
-> (NPieces -> Maybe NPieces) -> NPieces -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NPieces -> NPiecesByFile -> Maybe NPieces
forall k a. Ord k => k -> Map k a -> Maybe a
`Map.lookup` NPiecesByFile
opposingPawnYByX)
		) ([NPieces] -> Bool) -> (NPieces -> [NPieces]) -> NPieces -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NPieces -> [NPieces] -> [NPieces])
-> (NPieces, [NPieces]) -> [NPieces]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (:) ((NPieces, [NPieces]) -> [NPieces])
-> (NPieces -> (NPieces, [NPieces])) -> NPieces -> [NPieces]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
			NPieces -> NPieces
forall a. a -> a
id (NPieces -> NPieces)
-> (NPieces -> [NPieces]) -> NPieces -> (NPieces, [NPieces])
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& NPieces -> [NPieces]
Cartesian.Abscissa.getAdjacents
		) (NPieces -> Bool) -> NPieces -> Bool
forall a b. (a -> b) -> a -> b
$ Coordinates -> NPieces
Cartesian.Coordinates.getX Coordinates
coordinates
	) ([Coordinates] -> [Coordinates]) -> [Coordinates] -> [Coordinates]
forall a b. (a -> b) -> a -> b
$ LogicalColour -> [Coordinates]
findPawns LogicalColour
logicalColour
 ) [LogicalColour]
forall a. FixedMembership a => [a]
Property.FixedMembership.members where
	findPawns :: LogicalColour -> [Coordinates]
findPawns	= (CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
Attribute.Rank.Pawn) (CoordinatesByRank -> [Coordinates])
-> (LogicalColour -> CoordinatesByRank)
-> LogicalColour
-> [Coordinates]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> LogicalColour -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!)

-- | Self-documentation.
type Transformation	= CoordinatesByRankByLogicalColour -> CoordinatesByRankByLogicalColour

-- | Remove the specified /coordinates/ from those recorded for the specified /rank/.
deleteCoordinates
	:: Cartesian.Coordinates.Coordinates
	-> Attribute.Rank.Rank
	-> CoordinatesByRank
	-> CoordinatesByRank
deleteCoordinates :: Coordinates -> Rank -> CoordinatesByRank -> CoordinatesByRank
deleteCoordinates Coordinates
coordinates Rank
rank CoordinatesByRank
byRank	= CoordinatesByRank
byRank CoordinatesByRank -> [(Rank, [Coordinates])] -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)] -> a i e
// [(Rank
rank, Coordinates -> [Coordinates] -> [Coordinates]
forall a. Eq a => a -> [a] -> [a]
Data.List.delete Coordinates
coordinates ([Coordinates] -> [Coordinates]) -> [Coordinates] -> [Coordinates]
forall a b. (a -> b) -> a -> b
$ CoordinatesByRank
byRank CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
rank)]

-- | Adjust the array to reflect a new /move/.
movePiece
	:: Component.Move.Move
	-> Component.Piece.Piece						-- ^ The piece which moved.
	-> Maybe Attribute.Rank.Rank						-- ^ The (possibly promoted) rank to place at the destination.
	-> Either Cartesian.Coordinates.Coordinates (Maybe Attribute.Rank.Rank)	-- ^ Either the destination of any passed @Pawn@, or the /rank/ of any /piece/ taken.
	-> Transformation
movePiece :: Move
-> Piece
-> Maybe Rank
-> Either Coordinates (Maybe Rank)
-> Transformation
movePiece Move
move Piece
sourcePiece Maybe Rank
maybePromotionRank Either Coordinates (Maybe Rank)
eitherPassingPawnsDestinationOrMaybeTakenRank MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= ArrayByLogicalColour CoordinatesByRank
-> CoordinatesByRankByLogicalColour
MkCoordinatesByRankByLogicalColour (ArrayByLogicalColour CoordinatesByRank
 -> CoordinatesByRankByLogicalColour)
-> ArrayByLogicalColour CoordinatesByRank
-> CoordinatesByRankByLogicalColour
forall a b. (a -> b) -> a -> b
$ ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> [(LogicalColour, CoordinatesByRank)]
-> ArrayByLogicalColour CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)] -> a i e
// (
	(:) ((LogicalColour, CoordinatesByRank)
 -> [(LogicalColour, CoordinatesByRank)]
 -> [(LogicalColour, CoordinatesByRank)])
-> (Coordinates -> (LogicalColour, CoordinatesByRank))
-> Coordinates
-> [(LogicalColour, CoordinatesByRank)]
-> [(LogicalColour, CoordinatesByRank)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Coordinates -> Rank -> (LogicalColour, CoordinatesByRank)
`deleteOpponentsCoordinates` Rank
Attribute.Rank.Pawn) (Coordinates
 -> [(LogicalColour, CoordinatesByRank)]
 -> [(LogicalColour, CoordinatesByRank)])
-> (Maybe Rank
    -> [(LogicalColour, CoordinatesByRank)]
    -> [(LogicalColour, CoordinatesByRank)])
-> Either Coordinates (Maybe Rank)
-> [(LogicalColour, CoordinatesByRank)]
-> [(LogicalColour, CoordinatesByRank)]
forall (a :: * -> * -> *) b d c.
ArrowChoice a =>
a b d -> a c d -> a (Either b c) d
||| ([(LogicalColour, CoordinatesByRank)]
 -> [(LogicalColour, CoordinatesByRank)])
-> (Rank
    -> [(LogicalColour, CoordinatesByRank)]
    -> [(LogicalColour, CoordinatesByRank)])
-> Maybe Rank
-> [(LogicalColour, CoordinatesByRank)]
-> [(LogicalColour, CoordinatesByRank)]
forall b a. b -> (a -> b) -> Maybe a -> b
Data.Maybe.maybe [(LogicalColour, CoordinatesByRank)]
-> [(LogicalColour, CoordinatesByRank)]
forall a. a -> a
id {-quiet move-} (
		(:) ((LogicalColour, CoordinatesByRank)
 -> [(LogicalColour, CoordinatesByRank)]
 -> [(LogicalColour, CoordinatesByRank)])
-> (Rank -> (LogicalColour, CoordinatesByRank))
-> Rank
-> [(LogicalColour, CoordinatesByRank)]
-> [(LogicalColour, CoordinatesByRank)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Coordinates -> Rank -> (LogicalColour, CoordinatesByRank)
deleteOpponentsCoordinates Coordinates
destination
	) (Either Coordinates (Maybe Rank)
 -> [(LogicalColour, CoordinatesByRank)]
 -> [(LogicalColour, CoordinatesByRank)])
-> Either Coordinates (Maybe Rank)
-> [(LogicalColour, CoordinatesByRank)]
-> [(LogicalColour, CoordinatesByRank)]
forall a b. (a -> b) -> a -> b
$ Either Coordinates (Maybe Rank)
eitherPassingPawnsDestinationOrMaybeTakenRank
 ) [
	let
		byRank :: CoordinatesByRank
byRank	= ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> LogicalColour -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! LogicalColour
logicalColour
	in (
		LogicalColour
logicalColour,
		CoordinatesByRank
byRank CoordinatesByRank -> [(Rank, [Coordinates])] -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)] -> a i e
// ((Rank, [Coordinates]) -> [(Rank, [Coordinates])])
-> (Rank -> (Rank, [Coordinates]) -> [(Rank, [Coordinates])])
-> Maybe Rank
-> (Rank, [Coordinates])
-> [(Rank, [Coordinates])]
forall b a. b -> (a -> b) -> Maybe a -> b
Data.Maybe.maybe (
			(Rank, [Coordinates]) -> [(Rank, [Coordinates])]
forall (m :: * -> *) a. Monad m => a -> m a
return {-to List-monad-} ((Rank, [Coordinates]) -> [(Rank, [Coordinates])])
-> ((Rank, [Coordinates]) -> (Rank, [Coordinates]))
-> (Rank, [Coordinates])
-> [(Rank, [Coordinates])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Coordinates] -> [Coordinates])
-> (Rank, [Coordinates]) -> (Rank, [Coordinates])
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
Control.Arrow.second (Coordinates
destination Coordinates -> [Coordinates] -> [Coordinates]
forall a. a -> [a] -> [a]
:)	-- Add the destination to the mover.
		) (
			\Rank
promotionRank -> (:) (
				Rank
promotionRank,
				Coordinates
destination Coordinates -> [Coordinates] -> [Coordinates]
forall a. a -> [a] -> [a]
: CoordinatesByRank
byRank CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
promotionRank	-- Add the destination to the mover's promoted rank.
			) ([(Rank, [Coordinates])] -> [(Rank, [Coordinates])])
-> ((Rank, [Coordinates]) -> [(Rank, [Coordinates])])
-> (Rank, [Coordinates])
-> [(Rank, [Coordinates])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Rank, [Coordinates]) -> [(Rank, [Coordinates])]
forall (m :: * -> *) a. Monad m => a -> m a
return {-to List-monad-}
		) Maybe Rank
maybePromotionRank (
			Rank -> Rank
forall a. a -> a
id (Rank -> Rank)
-> (Rank -> [Coordinates]) -> Rank -> (Rank, [Coordinates])
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& Coordinates -> [Coordinates] -> [Coordinates]
forall a. Eq a => a -> [a] -> [a]
Data.List.delete (Move -> Coordinates
Component.Move.getSource Move
move) ([Coordinates] -> [Coordinates])
-> (Rank -> [Coordinates]) -> Rank -> [Coordinates]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CoordinatesByRank
byRank CoordinatesByRank -> Rank -> [Coordinates]
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!) (Rank -> (Rank, [Coordinates])) -> Rank -> (Rank, [Coordinates])
forall a b. (a -> b) -> a -> b
$ Piece -> Rank
Component.Piece.getRank Piece
sourcePiece
		)
	) -- Pair.
 ] where
	destination :: Coordinates
destination					= Move -> Coordinates
Component.Move.getDestination Move
move
	logicalColour :: LogicalColour
logicalColour					= Piece -> LogicalColour
Component.Piece.getLogicalColour Piece
sourcePiece
	deleteOpponentsCoordinates :: Coordinates -> Rank -> (LogicalColour, CoordinatesByRank)
deleteOpponentsCoordinates Coordinates
coordinates Rank
rank	= LogicalColour -> LogicalColour
forall a. a -> a
id (LogicalColour -> LogicalColour)
-> (LogicalColour -> CoordinatesByRank)
-> LogicalColour
-> (LogicalColour, CoordinatesByRank)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& Coordinates -> Rank -> CoordinatesByRank -> CoordinatesByRank
deleteCoordinates Coordinates
coordinates Rank
rank (CoordinatesByRank -> CoordinatesByRank)
-> (LogicalColour -> CoordinatesByRank)
-> LogicalColour
-> CoordinatesByRank
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ArrayByLogicalColour CoordinatesByRank
byLogicalColour ArrayByLogicalColour CoordinatesByRank
-> LogicalColour -> CoordinatesByRank
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!) (LogicalColour -> (LogicalColour, CoordinatesByRank))
-> LogicalColour -> (LogicalColour, CoordinatesByRank)
forall a b. (a -> b) -> a -> b
$ LogicalColour -> LogicalColour
forall a. Opposable a => a -> a
Property.Opposable.getOpposite LogicalColour
logicalColour

-- | Independently sort each list of /coordinates/.
sortCoordinates :: Transformation
sortCoordinates :: Transformation
sortCoordinates MkCoordinatesByRankByLogicalColour { deconstruct :: CoordinatesByRankByLogicalColour
-> ArrayByLogicalColour CoordinatesByRank
deconstruct = ArrayByLogicalColour CoordinatesByRank
byLogicalColour }	= ArrayByLogicalColour CoordinatesByRank
-> CoordinatesByRankByLogicalColour
MkCoordinatesByRankByLogicalColour (ArrayByLogicalColour CoordinatesByRank
 -> CoordinatesByRankByLogicalColour)
-> ArrayByLogicalColour CoordinatesByRank
-> CoordinatesByRankByLogicalColour
forall a b. (a -> b) -> a -> b
$ (CoordinatesByRank -> CoordinatesByRank)
-> ArrayByLogicalColour CoordinatesByRank
-> ArrayByLogicalColour CoordinatesByRank
forall (a :: * -> * -> *) e' e i.
(IArray a e', IArray a e, Ix i) =>
(e' -> e) -> a i e' -> a i e
Data.Array.IArray.amap (([Coordinates] -> [Coordinates])
-> CoordinatesByRank -> CoordinatesByRank
forall (a :: * -> * -> *) e' e i.
(IArray a e', IArray a e, Ix i) =>
(e' -> e) -> a i e' -> a i e
Data.Array.IArray.amap [Coordinates] -> [Coordinates]
forall a. Ord a => [a] -> [a]
Data.List.sort) ArrayByLogicalColour CoordinatesByRank
byLogicalColour