{-
	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@]	Defines the relative value of a specific /rank/ of piece, occupying a specific /coordinate/ on the board, at a specific stage in the game.
-}

module BishBosh.Component.PieceSquareByCoordinatesByRank(
-- * Types
-- ** Type-synonyms
--	PieceSquareValueByNPieces,
--	EitherPieceSquareValueByNPiecesByCoordinates,
	FindPieceSquareValue,
	FindPieceSquareValues,
-- ** Data-types
	PieceSquareByCoordinatesByRank(
--		MkPieceSquareByCoordinatesByRank,
--		deconstruct
	),
-- * Constants
	nPiecesBounds,
	gnuPlotComment,
-- * Functions
	findPieceSquareValue,
	findPieceSquareValues,
	interpolatePieceSquareValues,
	formatForGNUPlot,
-- ** Constructor
	mkPieceSquareByCoordinatesByRank
) where

import			Control.Arrow((&&&), (|||))
import			Data.Array.IArray((!))
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.Component.Piece		as Component.Piece
import qualified	BishBosh.Property.FixedMembership	as Property.FixedMembership
import qualified	BishBosh.Property.Reflectable		as Property.Reflectable
import qualified	BishBosh.Text.ShowList			as Text.ShowList
import qualified	BishBosh.Type.Count			as Type.Count
import qualified	BishBosh.Type.Length			as Type.Length
import qualified	BishBosh.Type.Mass			as Type.Mass
import qualified	Control.DeepSeq
import qualified	Data.Array.IArray
import qualified	Data.List

-- | The piece-square value may vary as the game progresses.
type PieceSquareValueByNPieces pieceSquareValue	= Data.Array.IArray.Array Type.Count.NPieces pieceSquareValue

-- | The bounds of the number of pieces on the board, at the end-game & opening-game respectively.
nPiecesBounds :: (Type.Count.NPieces, Type.Count.NPieces)
nPiecesBounds :: (NPieces, NPieces)
nPiecesBounds	= (
	NPieces
3 {-minimum sufficient material-},
	NPieces -> NPieces
forall a b. (Integral a, Num b) => a -> b
fromIntegral NPieces
Attribute.LogicalColour.nDistinctLogicalColours NPieces -> NPieces -> NPieces
forall a. Num a => a -> a -> a
* NPieces
Component.Piece.nPiecesPerSide
 )

-- | Self-documentation.
type EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue	= Either (
	Cartesian.Coordinates.ArrayByCoordinates x y pieceSquareValue	-- Uninterpolated.
 ) (
	Cartesian.Coordinates.ArrayByCoordinates x y (PieceSquareValueByNPieces pieceSquareValue)	-- Interpolated.
 )

-- | The value for each type of /piece/ of occupying each coordinate, at each stage in the lifetime of the game.
newtype PieceSquareByCoordinatesByRank x y pieceSquareValue	= MkPieceSquareByCoordinatesByRank {
	PieceSquareByCoordinatesByRank x y pieceSquareValue
-> ArrayByRank
     (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
deconstruct	:: Attribute.Rank.ArrayByRank (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
} deriving (PieceSquareByCoordinatesByRank x y pieceSquareValue
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> Bool
(PieceSquareByCoordinatesByRank x y pieceSquareValue
 -> PieceSquareByCoordinatesByRank x y pieceSquareValue -> Bool)
-> (PieceSquareByCoordinatesByRank x y pieceSquareValue
    -> PieceSquareByCoordinatesByRank x y pieceSquareValue -> Bool)
-> Eq (PieceSquareByCoordinatesByRank x y pieceSquareValue)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall x y pieceSquareValue.
(Enum x, Enum y, Ord x, Ord y, Eq pieceSquareValue) =>
PieceSquareByCoordinatesByRank x y pieceSquareValue
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> Bool
/= :: PieceSquareByCoordinatesByRank x y pieceSquareValue
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> Bool
$c/= :: forall x y pieceSquareValue.
(Enum x, Enum y, Ord x, Ord y, Eq pieceSquareValue) =>
PieceSquareByCoordinatesByRank x y pieceSquareValue
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> Bool
== :: PieceSquareByCoordinatesByRank x y pieceSquareValue
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> Bool
$c== :: forall x y pieceSquareValue.
(Enum x, Enum y, Ord x, Ord y, Eq pieceSquareValue) =>
PieceSquareByCoordinatesByRank x y pieceSquareValue
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> Bool
Eq, NPieces
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> ShowS
[PieceSquareByCoordinatesByRank x y pieceSquareValue] -> ShowS
PieceSquareByCoordinatesByRank x y pieceSquareValue -> String
(NPieces
 -> PieceSquareByCoordinatesByRank x y pieceSquareValue -> ShowS)
-> (PieceSquareByCoordinatesByRank x y pieceSquareValue -> String)
-> ([PieceSquareByCoordinatesByRank x y pieceSquareValue] -> ShowS)
-> Show (PieceSquareByCoordinatesByRank x y pieceSquareValue)
forall a.
(NPieces -> a -> ShowS)
-> (a -> String) -> ([a] -> ShowS) -> Show a
forall x y pieceSquareValue.
(Enum x, Enum y, Ord x, Ord y, Show x, Show y,
 Show pieceSquareValue) =>
NPieces
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> ShowS
forall x y pieceSquareValue.
(Enum x, Enum y, Ord x, Ord y, Show x, Show y,
 Show pieceSquareValue) =>
[PieceSquareByCoordinatesByRank x y pieceSquareValue] -> ShowS
forall x y pieceSquareValue.
(Enum x, Enum y, Ord x, Ord y, Show x, Show y,
 Show pieceSquareValue) =>
PieceSquareByCoordinatesByRank x y pieceSquareValue -> String
showList :: [PieceSquareByCoordinatesByRank x y pieceSquareValue] -> ShowS
$cshowList :: forall x y pieceSquareValue.
(Enum x, Enum y, Ord x, Ord y, Show x, Show y,
 Show pieceSquareValue) =>
[PieceSquareByCoordinatesByRank x y pieceSquareValue] -> ShowS
show :: PieceSquareByCoordinatesByRank x y pieceSquareValue -> String
$cshow :: forall x y pieceSquareValue.
(Enum x, Enum y, Ord x, Ord y, Show x, Show y,
 Show pieceSquareValue) =>
PieceSquareByCoordinatesByRank x y pieceSquareValue -> String
showsPrec :: NPieces
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> ShowS
$cshowsPrec :: forall x y pieceSquareValue.
(Enum x, Enum y, Ord x, Ord y, Show x, Show y,
 Show pieceSquareValue) =>
NPieces
-> PieceSquareByCoordinatesByRank x y pieceSquareValue -> ShowS
Show)

instance (
	Control.DeepSeq.NFData	pieceSquareValue,
	Control.DeepSeq.NFData	x,
	Control.DeepSeq.NFData	y
 ) => Control.DeepSeq.NFData (PieceSquareByCoordinatesByRank x y pieceSquareValue) where
	rnf :: PieceSquareByCoordinatesByRank x y pieceSquareValue -> ()
rnf MkPieceSquareByCoordinatesByRank { deconstruct :: forall x y pieceSquareValue.
PieceSquareByCoordinatesByRank x y pieceSquareValue
-> ArrayByRank
     (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
deconstruct = ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
byRank }	= ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
-> ()
forall a. NFData a => a -> ()
Control.DeepSeq.rnf ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
byRank

-- | Constructor.
mkPieceSquareByCoordinatesByRank
	:: (Attribute.Rank.Rank -> EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)	-- ^ Convert a /rank/ into either (a /pieceSquareValue/ or a /pieceSquareValue/ which linearly varies with the number of /piece/s remaining) by /coordinates/.
	-> PieceSquareByCoordinatesByRank x y pieceSquareValue
mkPieceSquareByCoordinatesByRank :: (Rank
 -> EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue)
-> PieceSquareByCoordinatesByRank x y pieceSquareValue
mkPieceSquareByCoordinatesByRank	= ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
-> PieceSquareByCoordinatesByRank x y pieceSquareValue
forall x y pieceSquareValue.
ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
-> PieceSquareByCoordinatesByRank x y pieceSquareValue
MkPieceSquareByCoordinatesByRank (ArrayByRank
   (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
 -> PieceSquareByCoordinatesByRank x y pieceSquareValue)
-> ((Rank
     -> EitherPieceSquareValueByNPiecesByCoordinates
          x y pieceSquareValue)
    -> ArrayByRank
         (EitherPieceSquareValueByNPiecesByCoordinates
            x y pieceSquareValue))
-> (Rank
    -> EitherPieceSquareValueByNPiecesByCoordinates
         x y pieceSquareValue)
-> PieceSquareByCoordinatesByRank x y pieceSquareValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue]
-> ArrayByRank
     (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
forall (a :: * -> * -> *) e. IArray a e => [e] -> a Rank e
Attribute.Rank.listArrayByRank ([EitherPieceSquareValueByNPiecesByCoordinates
    x y pieceSquareValue]
 -> ArrayByRank
      (EitherPieceSquareValueByNPiecesByCoordinates
         x y pieceSquareValue))
-> ((Rank
     -> EitherPieceSquareValueByNPiecesByCoordinates
          x y pieceSquareValue)
    -> [EitherPieceSquareValueByNPiecesByCoordinates
          x y pieceSquareValue])
-> (Rank
    -> EitherPieceSquareValueByNPiecesByCoordinates
         x y pieceSquareValue)
-> ArrayByRank
     (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Rank
 -> EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue)
-> [Rank]
-> [EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue]
forall a b. (a -> b) -> [a] -> [b]
`map` [Rank]
forall a. FixedMembership a => [a]
Property.FixedMembership.members)

-- | The type of a function which can find the required piece-square value.
type FindPieceSquareValue x y pieceSquareValue
	= Attribute.LogicalColour.LogicalColour		-- ^ The /piece/'s /logical colour/.
	-> Attribute.Rank.Rank				-- ^ The /piece/'s /rank/.
	-> Cartesian.Coordinates.Coordinates x y	-- ^ The /piece/'s location.
	-> pieceSquareValue

-- | Find the piece-square value, at a stage in the game's lifetime defined by the total number of pieces remaining, for the specified /rank/ & /coordinates/.
findPieceSquareValue :: (
	Enum	x,
	Enum	y,
	Ord	x,
	Ord	y
 )
	=> Type.Count.NPieces				-- ^ The progress through the game.
	-> Attribute.LogicalColour.LogicalColour	-- ^ The /piece/'s /logical colour/.
	-> Attribute.Rank.Rank				-- ^ The /piece/'s /rank/.
	-> Cartesian.Coordinates.Coordinates x y	-- ^ The /piece/'s location.
	-> PieceSquareByCoordinatesByRank x y pieceSquareValue
	-> pieceSquareValue
{-# SPECIALISE findPieceSquareValue
	:: Type.Count.NPieces
	-> Attribute.LogicalColour.LogicalColour
	-> Attribute.Rank.Rank
	-> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y
	-> PieceSquareByCoordinatesByRank Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue
	-> Type.Mass.PieceSquareValue
 #-}
findPieceSquareValue :: NPieces
-> LogicalColour
-> Rank
-> Coordinates x y
-> PieceSquareByCoordinatesByRank x y pieceSquareValue
-> pieceSquareValue
findPieceSquareValue NPieces
nPieces LogicalColour
logicalColour Rank
rank Coordinates x y
coordinates MkPieceSquareByCoordinatesByRank { deconstruct :: forall x y pieceSquareValue.
PieceSquareByCoordinatesByRank x y pieceSquareValue
-> ArrayByRank
     (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
deconstruct = ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
byRank }	= (
	(!) (Array (Coordinates x y) pieceSquareValue
 -> Coordinates x y -> pieceSquareValue)
-> (Array (Coordinates x y) (Array NPieces pieceSquareValue)
    -> Coordinates x y -> pieceSquareValue)
-> EitherPieceSquareValueByNPiecesByCoordinates
     x y pieceSquareValue
-> Coordinates x y
-> pieceSquareValue
forall (a :: * -> * -> *) b d c.
ArrowChoice a =>
a b d -> a c d -> a (Either b c) d
||| (
		\Array (Coordinates x y) (Array NPieces pieceSquareValue)
byNPiecesByCoordinates	-> (Array NPieces pieceSquareValue -> NPieces -> pieceSquareValue
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! NPieces
nPieces) (Array NPieces pieceSquareValue -> pieceSquareValue)
-> (Coordinates x y -> Array NPieces pieceSquareValue)
-> Coordinates x y
-> pieceSquareValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Array (Coordinates x y) (Array NPieces pieceSquareValue)
byNPiecesByCoordinates Array (Coordinates x y) (Array NPieces pieceSquareValue)
-> Coordinates x y -> Array NPieces pieceSquareValue
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!)
	) (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue
 -> Coordinates x y -> pieceSquareValue)
-> EitherPieceSquareValueByNPiecesByCoordinates
     x y pieceSquareValue
-> Coordinates x y
-> pieceSquareValue
forall a b. (a -> b) -> a -> b
$ ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
byRank ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
-> Rank
-> EitherPieceSquareValueByNPiecesByCoordinates
     x y pieceSquareValue
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
rank
 ) (Coordinates x y -> pieceSquareValue)
-> Coordinates x y -> pieceSquareValue
forall a b. (a -> b) -> a -> b
$ (
	if LogicalColour -> Bool
Attribute.LogicalColour.isBlack LogicalColour
logicalColour
		then Coordinates x y -> Coordinates x y
forall a. ReflectableOnX a => a -> a
Property.Reflectable.reflectOnX
		else Coordinates x y -> Coordinates x y
forall a. a -> a
id
 ) Coordinates x y
coordinates

-- | The type of a function which can find the required piece-square values.
type FindPieceSquareValues x y pieceSquareValue
	= Attribute.LogicalColour.LogicalColour		-- ^ The /piece/'s /logical colour/.
	-> Attribute.Rank.Rank				-- ^ The /piece/'s /rank/.
	-> [Cartesian.Coordinates.Coordinates x y]	-- ^ The locations of interest for the /piece/.
	-> [pieceSquareValue]

-- | Find the piece-square values, at a stage in the game's lifetime defined by the total number of pieces remaining, for the specified /rank/ & list of /coordinates/.
findPieceSquareValues :: (
	Enum	x,
	Enum	y,
	Ord	x,
	Ord	y
 )
	=> Type.Count.NPieces				-- ^ The progress through the game.
	-> Attribute.LogicalColour.LogicalColour	-- ^ The /piece/'s /logical colour/.
	-> Attribute.Rank.Rank				-- ^ The /piece/'s /rank/.
	-> [Cartesian.Coordinates.Coordinates x y]	-- ^ The locations of interest for the specified /piece/.
	-> PieceSquareByCoordinatesByRank x y pieceSquareValue
	-> [pieceSquareValue]
{-# SPECIALISE findPieceSquareValues
	:: Type.Count.NPieces
	-> Attribute.LogicalColour.LogicalColour
	-> Attribute.Rank.Rank
	-> [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y]
	-> PieceSquareByCoordinatesByRank Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue
	-> [Type.Mass.PieceSquareValue]
 #-}
findPieceSquareValues :: NPieces
-> LogicalColour
-> Rank
-> [Coordinates x y]
-> PieceSquareByCoordinatesByRank x y pieceSquareValue
-> [pieceSquareValue]
findPieceSquareValues NPieces
nPieces LogicalColour
logicalColour Rank
rank [Coordinates x y]
coordinatesList MkPieceSquareByCoordinatesByRank { deconstruct :: forall x y pieceSquareValue.
PieceSquareByCoordinatesByRank x y pieceSquareValue
-> ArrayByRank
     (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
deconstruct = ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
byRank }	= (
	(!) (Array (Coordinates x y) pieceSquareValue
 -> Coordinates x y -> pieceSquareValue)
-> (Array (Coordinates x y) (Array NPieces pieceSquareValue)
    -> Coordinates x y -> pieceSquareValue)
-> EitherPieceSquareValueByNPiecesByCoordinates
     x y pieceSquareValue
-> Coordinates x y
-> pieceSquareValue
forall (a :: * -> * -> *) b d c.
ArrowChoice a =>
a b d -> a c d -> a (Either b c) d
||| (
		\Array (Coordinates x y) (Array NPieces pieceSquareValue)
byNPiecesByCoordinates	-> (Array NPieces pieceSquareValue -> NPieces -> pieceSquareValue
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! NPieces
nPieces) (Array NPieces pieceSquareValue -> pieceSquareValue)
-> (Coordinates x y -> Array NPieces pieceSquareValue)
-> Coordinates x y
-> pieceSquareValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Array (Coordinates x y) (Array NPieces pieceSquareValue)
byNPiecesByCoordinates Array (Coordinates x y) (Array NPieces pieceSquareValue)
-> Coordinates x y -> Array NPieces pieceSquareValue
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!)
	) (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue
 -> Coordinates x y -> pieceSquareValue)
-> EitherPieceSquareValueByNPiecesByCoordinates
     x y pieceSquareValue
-> Coordinates x y
-> pieceSquareValue
forall a b. (a -> b) -> a -> b
$ ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
byRank ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
-> Rank
-> EitherPieceSquareValueByNPiecesByCoordinates
     x y pieceSquareValue
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Rank
rank
 ) (Coordinates x y -> pieceSquareValue)
-> [Coordinates x y] -> [pieceSquareValue]
forall a b. (a -> b) -> [a] -> [b]
`map` (
	if LogicalColour -> Bool
Attribute.LogicalColour.isBlack LogicalColour
logicalColour
		then (Coordinates x y -> Coordinates x y)
-> [Coordinates x y] -> [Coordinates x y]
forall a b. (a -> b) -> [a] -> [b]
map Coordinates x y -> Coordinates x y
forall a. ReflectableOnX a => a -> a
Property.Reflectable.reflectOnX
		else [Coordinates x y] -> [Coordinates x y]
forall a. a -> a
id
 ) [Coordinates x y]
coordinatesList

-- | Given the bounds over which two piece-square values vary as the game progresses from opening to end, return linearly interpolated values for all stages.
interpolatePieceSquareValues
	:: Fractional pieceSquareValue
	=> pieceSquareValue	-- ^ Opening-game.
	-> pieceSquareValue	-- ^ End-game.
	-> PieceSquareValueByNPieces pieceSquareValue
interpolatePieceSquareValues :: pieceSquareValue
-> pieceSquareValue -> PieceSquareValueByNPieces pieceSquareValue
interpolatePieceSquareValues pieceSquareValue
openingGame pieceSquareValue
endGame	= (NPieces, NPieces)
-> [pieceSquareValue] -> PieceSquareValueByNPieces pieceSquareValue
forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [e] -> a i e
Data.Array.IArray.listArray (NPieces, NPieces)
nPiecesBounds ([pieceSquareValue] -> PieceSquareValueByNPieces pieceSquareValue)
-> ([NPieces] -> [pieceSquareValue])
-> [NPieces]
-> PieceSquareValueByNPieces pieceSquareValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (NPieces -> pieceSquareValue) -> [NPieces] -> [pieceSquareValue]
forall a b. (a -> b) -> [a] -> [b]
map (
	(pieceSquareValue -> pieceSquareValue -> pieceSquareValue)
-> (pieceSquareValue, pieceSquareValue) -> pieceSquareValue
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry pieceSquareValue -> pieceSquareValue -> pieceSquareValue
forall a. Num a => a -> a -> a
(+) ((pieceSquareValue, pieceSquareValue) -> pieceSquareValue)
-> (NPieces -> (pieceSquareValue, pieceSquareValue))
-> NPieces
-> pieceSquareValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
		(pieceSquareValue -> pieceSquareValue -> pieceSquareValue
forall a. Num a => a -> a -> a
* pieceSquareValue
openingGame) (pieceSquareValue -> pieceSquareValue)
-> (pieceSquareValue -> pieceSquareValue)
-> pieceSquareValue
-> (pieceSquareValue, pieceSquareValue)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& (pieceSquareValue -> pieceSquareValue -> pieceSquareValue
forall a. Num a => a -> a -> a
* pieceSquareValue
endGame) (pieceSquareValue -> pieceSquareValue)
-> (pieceSquareValue -> pieceSquareValue)
-> pieceSquareValue
-> pieceSquareValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (pieceSquareValue
1 pieceSquareValue -> pieceSquareValue -> pieceSquareValue
forall a. Num a => a -> a -> a
-)
	) (pieceSquareValue -> (pieceSquareValue, pieceSquareValue))
-> (NPieces -> pieceSquareValue)
-> NPieces
-> (pieceSquareValue, pieceSquareValue)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
		pieceSquareValue -> pieceSquareValue -> pieceSquareValue
forall a. Fractional a => a -> a -> a
/ NPieces -> pieceSquareValue
forall a b. (Integral a, Num b) => a -> b
fromIntegral (
			(NPieces -> NPieces -> NPieces) -> (NPieces, NPieces) -> NPieces
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry NPieces -> NPieces -> NPieces
forall a. Num a => a -> a -> a
subtract (NPieces, NPieces)
nPiecesBounds	-- N.B.: this can't reasonably be zero.
		) -- map into the closed unit-interval [0,1].
	) (pieceSquareValue -> pieceSquareValue)
-> (NPieces -> pieceSquareValue) -> NPieces -> pieceSquareValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NPieces -> pieceSquareValue
forall a b. (Integral a, Num b) => a -> b
fromIntegral (NPieces -> pieceSquareValue)
-> (NPieces -> NPieces) -> NPieces -> pieceSquareValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NPieces -> NPieces -> NPieces
forall a. Num a => a -> a -> a
subtract (
		(NPieces, NPieces) -> NPieces
forall a b. (a, b) -> a
fst {-minimum-} (NPieces, NPieces)
nPiecesBounds
	)
 ) ([NPieces] -> PieceSquareValueByNPieces pieceSquareValue)
-> [NPieces] -> PieceSquareValueByNPieces pieceSquareValue
forall a b. (a -> b) -> a -> b
$ (NPieces -> NPieces -> [NPieces])
-> (NPieces, NPieces) -> [NPieces]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry NPieces -> NPieces -> [NPieces]
forall a. Enum a => a -> a -> [a]
enumFromTo (NPieces, NPieces)
nPiecesBounds

-- | The character used in __GNUPlot__ to denote a comment.
gnuPlotComment :: Char
gnuPlotComment :: Char
gnuPlotComment	= Char
'#'

-- | Format the data for input to __GNUPlot__.
formatForGNUPlot :: (
	Enum	x,
	Enum	y,
	Ord	x,
	Ord	y
 )
	=> (pieceSquareValue -> ShowS)						-- ^ Format a /pieceSquareValue/.
	-> ShowS								-- ^ The column-delimiter.
	-> (PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue)	-- ^ Select one /pieceSquareValue/ from interpolated values.
	-> PieceSquareByCoordinatesByRank x y pieceSquareValue
	-> ShowS
formatForGNUPlot :: (pieceSquareValue -> ShowS)
-> ShowS
-> (PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue)
-> PieceSquareByCoordinatesByRank x y pieceSquareValue
-> ShowS
formatForGNUPlot pieceSquareValue -> ShowS
pieceSquareValueFormatter ShowS
columnDelimiter PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue
selector MkPieceSquareByCoordinatesByRank { deconstruct :: forall x y pieceSquareValue.
PieceSquareByCoordinatesByRank x y pieceSquareValue
-> ArrayByRank
     (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
deconstruct = ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
byRank }	= (
	[ShowS] -> ShowS
showsRow (
		Char -> ShowS
showChar Char
gnuPlotComment ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
'x' ShowS -> [ShowS] -> [ShowS]
forall a. a -> [a] -> [a]
: Char -> ShowS
showChar Char
'y' ShowS -> [ShowS] -> [ShowS]
forall a. a -> [a] -> [a]
: (Rank -> ShowS) -> [Rank] -> [ShowS]
forall a b. (a -> b) -> [a] -> [b]
map Rank -> ShowS
forall a. Show a => a -> ShowS
shows [Rank]
Attribute.Rank.range	-- Header comment.
	) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
 ) (ShowS -> ShowS)
-> ([EitherPieceSquareValueByNPiecesByCoordinates
       x y pieceSquareValue]
    -> ShowS)
-> [EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue]
-> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Coordinates NPieces NPieces, [pieceSquareValue])
 -> ShowS -> ShowS)
-> ShowS
-> [(Coordinates NPieces NPieces, [pieceSquareValue])]
-> ShowS
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (
	\(Coordinates NPieces NPieces
coordinates, [pieceSquareValue]
byRank') ShowS
showS	-> let
		(NPieces
x, NPieces
y)	= Coordinates NPieces NPieces -> NPieces
forall x y. Coordinates x y -> x
Cartesian.Coordinates.getX (Coordinates NPieces NPieces -> NPieces)
-> (Coordinates NPieces NPieces -> NPieces)
-> Coordinates NPieces NPieces
-> (NPieces, NPieces)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& Coordinates NPieces NPieces -> NPieces
forall x y. Coordinates x y -> y
Cartesian.Coordinates.getY (Coordinates NPieces NPieces -> (NPieces, NPieces))
-> Coordinates NPieces NPieces -> (NPieces, NPieces)
forall a b. (a -> b) -> a -> b
$ Coordinates NPieces NPieces
coordinates
	in [ShowS] -> ShowS
showsRow (
		NPieces -> ShowS
forall a. Show a => a -> ShowS
shows NPieces
x ShowS -> [ShowS] -> [ShowS]
forall a. a -> [a] -> [a]
: NPieces -> ShowS
forall a. Show a => a -> ShowS
shows NPieces
y ShowS -> [ShowS] -> [ShowS]
forall a. a -> [a] -> [a]
: (pieceSquareValue -> ShowS) -> [pieceSquareValue] -> [ShowS]
forall a b. (a -> b) -> [a] -> [b]
map pieceSquareValue -> ShowS
pieceSquareValueFormatter [pieceSquareValue]
byRank'
	) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
		if NPieces
x NPieces -> NPieces -> Bool
forall a. Eq a => a -> a -> Bool
== NPieces
forall x. Enum x => x
Cartesian.Abscissa.xMax
			then ShowS
terminateRow	-- Separate isolines.
			else ShowS
forall a. a -> a
id
	) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
showS
 ) ShowS
forall a. a -> a
id ([(Coordinates NPieces NPieces, [pieceSquareValue])] -> ShowS)
-> ([EitherPieceSquareValueByNPiecesByCoordinates
       x y pieceSquareValue]
    -> [(Coordinates NPieces NPieces, [pieceSquareValue])])
-> [EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue]
-> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Coordinates NPieces NPieces]
-> [[pieceSquareValue]]
-> [(Coordinates NPieces NPieces, [pieceSquareValue])]
forall a b. [a] -> [b] -> [(a, b)]
zip (
	[Coordinates NPieces NPieces]
forall a. FixedMembership a => [a]
Property.FixedMembership.members	:: [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y]
 ) ([[pieceSquareValue]]
 -> [(Coordinates NPieces NPieces, [pieceSquareValue])])
-> ([EitherPieceSquareValueByNPiecesByCoordinates
       x y pieceSquareValue]
    -> [[pieceSquareValue]])
-> [EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue]
-> [(Coordinates NPieces NPieces, [pieceSquareValue])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[pieceSquareValue]] -> [[pieceSquareValue]]
forall a. [[a]] -> [[a]]
Data.List.transpose ([[pieceSquareValue]] -> [[pieceSquareValue]])
-> ([EitherPieceSquareValueByNPiecesByCoordinates
       x y pieceSquareValue]
    -> [[pieceSquareValue]])
-> [EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue]
-> [[pieceSquareValue]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue
 -> [pieceSquareValue])
-> [EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue]
-> [[pieceSquareValue]]
forall a b. (a -> b) -> [a] -> [b]
map (
	Array (Coordinates x y) pieceSquareValue -> [pieceSquareValue]
forall (a :: * -> * -> *) e i. (IArray a e, Ix i) => a i e -> [e]
Data.Array.IArray.elems (Array (Coordinates x y) pieceSquareValue -> [pieceSquareValue])
-> (Array
      (Coordinates x y) (PieceSquareValueByNPieces pieceSquareValue)
    -> [pieceSquareValue])
-> EitherPieceSquareValueByNPiecesByCoordinates
     x y pieceSquareValue
-> [pieceSquareValue]
forall (a :: * -> * -> *) b d c.
ArrowChoice a =>
a b d -> a c d -> a (Either b c) d
||| (PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue)
-> [PieceSquareValueByNPieces pieceSquareValue]
-> [pieceSquareValue]
forall a b. (a -> b) -> [a] -> [b]
map PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue
selector {-select one pieceSquareValue from interpolated values-} ([PieceSquareValueByNPieces pieceSquareValue]
 -> [pieceSquareValue])
-> (Array
      (Coordinates x y) (PieceSquareValueByNPieces pieceSquareValue)
    -> [PieceSquareValueByNPieces pieceSquareValue])
-> Array
     (Coordinates x y) (PieceSquareValueByNPieces pieceSquareValue)
-> [pieceSquareValue]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Array
  (Coordinates x y) (PieceSquareValueByNPieces pieceSquareValue)
-> [PieceSquareValueByNPieces pieceSquareValue]
forall (a :: * -> * -> *) e i. (IArray a e, Ix i) => a i e -> [e]
Data.Array.IArray.elems {-ByCoordinates-}
 ) ([EitherPieceSquareValueByNPiecesByCoordinates
    x y pieceSquareValue]
 -> ShowS)
-> [EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue]
-> ShowS
forall a b. (a -> b) -> a -> b
$ ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
-> [EitherPieceSquareValueByNPiecesByCoordinates
      x y pieceSquareValue]
forall (a :: * -> * -> *) e i. (IArray a e, Ix i) => a i e -> [e]
Data.Array.IArray.elems {-ByRank-} ArrayByRank
  (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)
byRank where
	terminateRow :: ShowS
terminateRow	= Char -> ShowS
showChar Char
'\n'
	showsRow :: [ShowS] -> ShowS
showsRow	= ShowS -> ShowS -> ShowS -> [ShowS] -> ShowS
Text.ShowList.showsDelimitedList ShowS
columnDelimiter ShowS
forall a. a -> a
id ShowS
terminateRow