{-
	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 weight associated with each criterion.
-}

module BishBosh.Input.CriteriaWeights(
-- * Types
-- ** Type-synonyms
--	Transformation,
-- ** Data-types
	CriteriaWeights(
--		MkCriteriaWeights,
		getWeightOfMaterial,
		getWeightOfMobility,
		getWeightOfPieceSquareValue,
		getWeightOfCastlingPotential,
		getWeightOfDefence,
		getWeightOfDoubledPawns,
		getWeightOfIsolatedPawns,
		getWeightOfPassedPawns
	),
-- * Constants
	tag,
	weightOfMaterialTag,
--	weightOfMobilityTag,
	weightOfPieceSquareValueTag,
--	weightOfCastlingPotentialTag,
--	weightOfDefenceTag,
--	weightOfDoubledPawnsTag,
--	weightOfIsolatedPawnsTag,
--	weightOfPassedPawnsTag,
-- * Functions
	calculateWeightedMean,
	normalise,
-- ** Constructor
	mkCriteriaWeights
) where

import qualified	BishBosh.Data.Exception				as Data.Exception
import qualified	BishBosh.Metric.CriterionValue			as Metric.CriterionValue
import qualified	BishBosh.Metric.CriterionWeight			as Metric.CriterionWeight
import qualified	BishBosh.Metric.WeightedMeanAndCriterionValues	as Metric.WeightedMeanAndCriterionValues
import qualified	BishBosh.Property.ShowFloat			as Property.ShowFloat
import qualified	BishBosh.Text.ShowList				as Text.ShowList
import qualified	Control.Arrow
import qualified	Control.DeepSeq
import qualified	Control.Exception
import qualified	Data.Default
import qualified	Text.XML.HXT.Arrow.Pickle			as HXT

-- | Used to qualify the XML.
tag :: String
tag :: String
tag				= String
"criteriaWeights"

-- | Used to qualify the XML.
weightOfMaterialTag :: String
weightOfMaterialTag :: String
weightOfMaterialTag		= String
"material"

-- | Used to qualify the XML.
weightOfMobilityTag :: String
weightOfMobilityTag :: String
weightOfMobilityTag		= String
"mobility"

-- | Used to qualify the XML.
weightOfPieceSquareValueTag :: String
weightOfPieceSquareValueTag :: String
weightOfPieceSquareValueTag	= String
"pieceSquareValue"

-- | Used to qualify the XML.
weightOfCastlingPotentialTag :: String
weightOfCastlingPotentialTag :: String
weightOfCastlingPotentialTag	= String
"castlingPotential"

-- | Used to qualify the XML.
weightOfDefenceTag :: String
weightOfDefenceTag :: String
weightOfDefenceTag		= String
"defence"

-- | Used to qualify the XML.
weightOfDoubledPawnsTag :: String
weightOfDoubledPawnsTag :: String
weightOfDoubledPawnsTag		= String
"doubledPawns"

-- | Used to qualify the XML.
weightOfIsolatedPawnsTag :: String
weightOfIsolatedPawnsTag :: String
weightOfIsolatedPawnsTag	= String
"isolatedPawns"

-- | Used to qualify the XML.
weightOfPassedPawnsTag :: String
weightOfPassedPawnsTag :: String
weightOfPassedPawnsTag		= String
"passedPawns"

{- |
	* The weight of various criteria used to select a /move/ from alternatives, at a specific point in the game.

	* CAVEAT: these weights determine the effective value of /isolated/ or /doubled/ @Pawn@s,
	& this value shouldn't be less than their weighted normalised /rank-value/, otherwise sacrifice would be beneficial.
-}
data CriteriaWeights	= MkCriteriaWeights {
	CriteriaWeights -> CriterionWeight
getWeightOfMaterial		:: Metric.CriterionWeight.CriterionWeight,	-- ^ The arithmetic difference between the total /rank-value/ of the /piece/s currently in play on either side; <https://www.chessprogramming.org/Material>.
	CriteriaWeights -> CriterionWeight
getWeightOfMobility		:: Metric.CriterionWeight.CriterionWeight,	-- ^ The arithmetic difference between the reciprocal of the number of destinations available to the /piece/s of either side. N.B. this weight can be derived from 'getWeightOfMaterial' since losing a @Queen@ is less significant than reducing mobility to zero; <https://www.chessprogramming.org/Mobility>.
	CriteriaWeights -> CriterionWeight
getWeightOfPieceSquareValue	:: Metric.CriterionWeight.CriterionWeight,	-- ^ The arithmetic difference in the values of the squares occupied by the pieces of either side.
	CriteriaWeights -> CriterionWeight
getWeightOfCastlingPotential	:: Metric.CriterionWeight.CriterionWeight,	-- ^ Whether each player has been permanently prevented from /Castling/.
	CriteriaWeights -> CriterionWeight
getWeightOfDefence		:: Metric.CriterionWeight.CriterionWeight,	-- ^ The arithmetic difference between the number of /piece/s defending each of one's own, compared with the opponent.
	CriteriaWeights -> CriterionWeight
getWeightOfDoubledPawns		:: Metric.CriterionWeight.CriterionWeight,	-- ^ The arithmetic difference between the total number of /doubled/ @Pawn@s on either side; <https://www.chessprogramming.org/Doubled_Pawn>.
	CriteriaWeights -> CriterionWeight
getWeightOfIsolatedPawns	:: Metric.CriterionWeight.CriterionWeight,	-- ^ The arithmetic difference between the total number of /isolated/ @Pawn@s on either side; <https://www.chessprogramming.org/Isolated_Pawn>.
	CriteriaWeights -> CriterionWeight
getWeightOfPassedPawns		:: Metric.CriterionWeight.CriterionWeight	-- ^ The arithmetic difference between the total number of /passed/ @Pawn@s on either side; <https://www.chessprogramming.org/Passed_Pawn>.
} deriving (CriteriaWeights -> CriteriaWeights -> Bool
(CriteriaWeights -> CriteriaWeights -> Bool)
-> (CriteriaWeights -> CriteriaWeights -> Bool)
-> Eq CriteriaWeights
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CriteriaWeights -> CriteriaWeights -> Bool
$c/= :: CriteriaWeights -> CriteriaWeights -> Bool
== :: CriteriaWeights -> CriteriaWeights -> Bool
$c== :: CriteriaWeights -> CriteriaWeights -> Bool
Eq, Int -> CriteriaWeights -> ShowS
[CriteriaWeights] -> ShowS
CriteriaWeights -> String
(Int -> CriteriaWeights -> ShowS)
-> (CriteriaWeights -> String)
-> ([CriteriaWeights] -> ShowS)
-> Show CriteriaWeights
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CriteriaWeights] -> ShowS
$cshowList :: [CriteriaWeights] -> ShowS
show :: CriteriaWeights -> String
$cshow :: CriteriaWeights -> String
showsPrec :: Int -> CriteriaWeights -> ShowS
$cshowsPrec :: Int -> CriteriaWeights -> ShowS
Show)

-- | Smart constructor.
mkCriteriaWeights
	:: Metric.CriterionWeight.CriterionWeight	-- ^ /material/.
	-> Metric.CriterionWeight.CriterionWeight	-- ^ /mobility/.
	-> Metric.CriterionWeight.CriterionWeight	-- ^ /pieceSquareValue/.
	-> Metric.CriterionWeight.CriterionWeight	-- ^ /castlingPotential/.
	-> Metric.CriterionWeight.CriterionWeight	-- ^ /defence/.
	-> Metric.CriterionWeight.CriterionWeight	-- ^ /doubledPawns/.
	-> Metric.CriterionWeight.CriterionWeight	-- ^ /isolatedPawns/.
	-> Metric.CriterionWeight.CriterionWeight	-- ^ /passedPawns/.
	-> CriteriaWeights
mkCriteriaWeights :: CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriteriaWeights
mkCriteriaWeights CriterionWeight
a CriterionWeight
b CriterionWeight
c CriterionWeight
d CriterionWeight
e CriterionWeight
f CriterionWeight
g CriterionWeight
h
	| CriteriaWeights
criteriaWeights CriteriaWeights -> CriteriaWeights -> Bool
forall a. Eq a => a -> a -> Bool
== CriteriaWeights
forall a. Bounded a => a
minBound	= Exception -> CriteriaWeights
forall a e. Exception e => e -> a
Control.Exception.throw (Exception -> CriteriaWeights) -> Exception -> CriteriaWeights
forall a b. (a -> b) -> a -> b
$ String -> Exception
Data.Exception.mkInvalidDatum String
"BishBosh.Input.CriteriaWeights.mkCriteriaWeights:\tall weights are zero."
	| Bool
otherwise			= CriteriaWeights
criteriaWeights
	where
		criteriaWeights :: CriteriaWeights
criteriaWeights	= CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriteriaWeights
MkCriteriaWeights CriterionWeight
a CriterionWeight
b CriterionWeight
c CriterionWeight
d CriterionWeight
e CriterionWeight
f CriterionWeight
g CriterionWeight
h

instance Property.ShowFloat.ShowFloat CriteriaWeights where
	showsFloat :: (Double -> ShowS) -> CriteriaWeights -> ShowS
showsFloat Double -> ShowS
fromDouble MkCriteriaWeights {
		getWeightOfMaterial :: CriteriaWeights -> CriterionWeight
getWeightOfMaterial		= CriterionWeight
weightOfMaterial,
		getWeightOfMobility :: CriteriaWeights -> CriterionWeight
getWeightOfMobility		= CriterionWeight
weightOfMobility,
		getWeightOfPieceSquareValue :: CriteriaWeights -> CriterionWeight
getWeightOfPieceSquareValue	= CriterionWeight
weightOfPieceSquareValue,
		getWeightOfCastlingPotential :: CriteriaWeights -> CriterionWeight
getWeightOfCastlingPotential	= CriterionWeight
weightOfCastlingPotential,
		getWeightOfDefence :: CriteriaWeights -> CriterionWeight
getWeightOfDefence		= CriterionWeight
weightOfDefence,
		getWeightOfDoubledPawns :: CriteriaWeights -> CriterionWeight
getWeightOfDoubledPawns		= CriterionWeight
weightOfDoubledPawns,
		getWeightOfIsolatedPawns :: CriteriaWeights -> CriterionWeight
getWeightOfIsolatedPawns	= CriterionWeight
weightOfIsolatedPawns,
		getWeightOfPassedPawns :: CriteriaWeights -> CriterionWeight
getWeightOfPassedPawns		= CriterionWeight
weightOfPassedPawns
	} = [(String, ShowS)] -> ShowS
Text.ShowList.showsAssociationList' ([(String, ShowS)] -> ShowS) -> [(String, ShowS)] -> ShowS
forall a b. (a -> b) -> a -> b
$ ((String, CriterionWeight) -> (String, ShowS))
-> [(String, CriterionWeight)] -> [(String, ShowS)]
forall a b. (a -> b) -> [a] -> [b]
map (
		(CriterionWeight -> ShowS)
-> (String, CriterionWeight) -> (String, ShowS)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
Control.Arrow.second ((CriterionWeight -> ShowS)
 -> (String, CriterionWeight) -> (String, ShowS))
-> (CriterionWeight -> ShowS)
-> (String, CriterionWeight)
-> (String, ShowS)
forall a b. (a -> b) -> a -> b
$ Double -> ShowS
fromDouble (Double -> ShowS)
-> (CriterionWeight -> Double) -> CriterionWeight -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CriterionWeight -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac
	 ) [
		(
			String
weightOfMaterialTag,		CriterionWeight
weightOfMaterial
		), (
			String
weightOfMobilityTag,		CriterionWeight
weightOfMobility
		), (
			String
weightOfPieceSquareValueTag,	CriterionWeight
weightOfPieceSquareValue
		), (
			String
weightOfCastlingPotentialTag,	CriterionWeight
weightOfCastlingPotential
		), (
			String
weightOfDefenceTag,		CriterionWeight
weightOfDefence
		), (
			String
weightOfDoubledPawnsTag,	CriterionWeight
weightOfDoubledPawns
		), (
			String
weightOfIsolatedPawnsTag,	CriterionWeight
weightOfIsolatedPawns
		), (
			String
weightOfPassedPawnsTag,		CriterionWeight
weightOfPassedPawns
		)
	 ]

instance Data.Default.Default CriteriaWeights where
	def :: CriteriaWeights
def = MkCriteriaWeights :: CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriteriaWeights
MkCriteriaWeights {
		getWeightOfMaterial :: CriterionWeight
getWeightOfMaterial		= CriterionWeight
forall a. Bounded a => a
maxBound,
		getWeightOfMobility :: CriterionWeight
getWeightOfMobility		= CriterionWeight
forall a. Default a => a
Data.Default.def,
		getWeightOfPieceSquareValue :: CriterionWeight
getWeightOfPieceSquareValue	= CriterionWeight
forall a. Default a => a
Data.Default.def,
		getWeightOfCastlingPotential :: CriterionWeight
getWeightOfCastlingPotential	= CriterionWeight
forall a. Default a => a
Data.Default.def,
		getWeightOfDefence :: CriterionWeight
getWeightOfDefence		= CriterionWeight
forall a. Default a => a
Data.Default.def,
		getWeightOfDoubledPawns :: CriterionWeight
getWeightOfDoubledPawns		= CriterionWeight
forall a. Default a => a
Data.Default.def,
		getWeightOfIsolatedPawns :: CriterionWeight
getWeightOfIsolatedPawns	= CriterionWeight
forall a. Default a => a
Data.Default.def,
		getWeightOfPassedPawns :: CriterionWeight
getWeightOfPassedPawns		= CriterionWeight
forall a. Default a => a
Data.Default.def
	}

instance Control.DeepSeq.NFData CriteriaWeights where
	rnf :: CriteriaWeights -> ()
rnf (MkCriteriaWeights CriterionWeight
a CriterionWeight
b CriterionWeight
c CriterionWeight
d CriterionWeight
e CriterionWeight
f CriterionWeight
g CriterionWeight
h)	= [CriterionWeight] -> ()
forall a. NFData a => a -> ()
Control.DeepSeq.rnf [CriterionWeight
a, CriterionWeight
b, CriterionWeight
c, CriterionWeight
d, CriterionWeight
e, CriterionWeight
f, CriterionWeight
g, CriterionWeight
h]

instance Bounded CriteriaWeights where
	maxBound :: CriteriaWeights
maxBound	= CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriteriaWeights
MkCriteriaWeights CriterionWeight
forall a. Bounded a => a
maxBound CriterionWeight
forall a. Bounded a => a
maxBound CriterionWeight
forall a. Bounded a => a
maxBound CriterionWeight
forall a. Bounded a => a
maxBound CriterionWeight
forall a. Bounded a => a
maxBound CriterionWeight
forall a. Bounded a => a
maxBound CriterionWeight
forall a. Bounded a => a
maxBound CriterionWeight
forall a. Bounded a => a
maxBound
	minBound :: CriteriaWeights
minBound	= CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriteriaWeights
MkCriteriaWeights CriterionWeight
forall a. Bounded a => a
minBound CriterionWeight
forall a. Bounded a => a
minBound CriterionWeight
forall a. Bounded a => a
minBound CriterionWeight
forall a. Bounded a => a
minBound CriterionWeight
forall a. Bounded a => a
minBound CriterionWeight
forall a. Bounded a => a
minBound CriterionWeight
forall a. Bounded a => a
minBound CriterionWeight
forall a. Bounded a => a
minBound

instance HXT.XmlPickler CriteriaWeights where
	xpickle :: PU CriteriaWeights
xpickle	= CriteriaWeights -> PU CriteriaWeights -> PU CriteriaWeights
forall a. Eq a => a -> PU a -> PU a
HXT.xpDefault CriteriaWeights
forall a. Default a => a
Data.Default.def (PU CriteriaWeights -> PU CriteriaWeights)
-> (PU CriteriaWeights -> PU CriteriaWeights)
-> PU CriteriaWeights
-> PU CriteriaWeights
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> PU CriteriaWeights -> PU CriteriaWeights
forall a. String -> PU a -> PU a
HXT.xpElem String
tag (PU CriteriaWeights -> PU CriteriaWeights)
-> PU CriteriaWeights -> PU CriteriaWeights
forall a b. (a -> b) -> a -> b
$ ((CriterionWeight, CriterionWeight, CriterionWeight,
  CriterionWeight, CriterionWeight, CriterionWeight, CriterionWeight,
  CriterionWeight)
 -> CriteriaWeights,
 CriteriaWeights
 -> (CriterionWeight, CriterionWeight, CriterionWeight,
     CriterionWeight, CriterionWeight, CriterionWeight, CriterionWeight,
     CriterionWeight))
-> PU
     (CriterionWeight, CriterionWeight, CriterionWeight,
      CriterionWeight, CriterionWeight, CriterionWeight, CriterionWeight,
      CriterionWeight)
-> PU CriteriaWeights
forall a b. (a -> b, b -> a) -> PU a -> PU b
HXT.xpWrap (
		\(CriterionWeight
a, CriterionWeight
b, CriterionWeight
c, CriterionWeight
d, CriterionWeight
e, CriterionWeight
f, CriterionWeight
g, CriterionWeight
h) -> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriteriaWeights
mkCriteriaWeights CriterionWeight
a CriterionWeight
b CriterionWeight
c CriterionWeight
d CriterionWeight
e CriterionWeight
f CriterionWeight
g CriterionWeight
h,	-- Construct.
		\MkCriteriaWeights {
			getWeightOfMaterial :: CriteriaWeights -> CriterionWeight
getWeightOfMaterial		= CriterionWeight
weightOfMaterial,
			getWeightOfMobility :: CriteriaWeights -> CriterionWeight
getWeightOfMobility		= CriterionWeight
weightOfMobility,
			getWeightOfPieceSquareValue :: CriteriaWeights -> CriterionWeight
getWeightOfPieceSquareValue	= CriterionWeight
weightOfPieceSquareValue,
			getWeightOfCastlingPotential :: CriteriaWeights -> CriterionWeight
getWeightOfCastlingPotential	= CriterionWeight
weightOfCastlingPotential,
			getWeightOfDefence :: CriteriaWeights -> CriterionWeight
getWeightOfDefence		= CriterionWeight
weightOfDefence,
			getWeightOfDoubledPawns :: CriteriaWeights -> CriterionWeight
getWeightOfDoubledPawns		= CriterionWeight
weightOfDoubledPawns,
			getWeightOfIsolatedPawns :: CriteriaWeights -> CriterionWeight
getWeightOfIsolatedPawns	= CriterionWeight
weightOfIsolatedPawns,
			getWeightOfPassedPawns :: CriteriaWeights -> CriterionWeight
getWeightOfPassedPawns		= CriterionWeight
weightOfPassedPawns
		} -> (
			CriterionWeight
weightOfMaterial,
			CriterionWeight
weightOfMobility,
			CriterionWeight
weightOfPieceSquareValue,
			CriterionWeight
weightOfCastlingPotential,
			CriterionWeight
weightOfDefence,
			CriterionWeight
weightOfDoubledPawns,
			CriterionWeight
weightOfIsolatedPawns,
			CriterionWeight
weightOfPassedPawns
		) -- Deconstruct.
	 ) (PU
   (CriterionWeight, CriterionWeight, CriterionWeight,
    CriterionWeight, CriterionWeight, CriterionWeight, CriterionWeight,
    CriterionWeight)
 -> PU CriteriaWeights)
-> PU
     (CriterionWeight, CriterionWeight, CriterionWeight,
      CriterionWeight, CriterionWeight, CriterionWeight, CriterionWeight,
      CriterionWeight)
-> PU CriteriaWeights
forall a b. (a -> b) -> a -> b
$ PU CriterionWeight
-> PU CriterionWeight
-> PU CriterionWeight
-> PU CriterionWeight
-> PU CriterionWeight
-> PU CriterionWeight
-> PU CriterionWeight
-> PU CriterionWeight
-> PU
     (CriterionWeight, CriterionWeight, CriterionWeight,
      CriterionWeight, CriterionWeight, CriterionWeight, CriterionWeight,
      CriterionWeight)
forall a b c d e f g h.
PU a
-> PU b
-> PU c
-> PU d
-> PU e
-> PU f
-> PU g
-> PU h
-> PU (a, b, c, d, e, f, g, h)
HXT.xp8Tuple (
		String -> PU CriterionWeight
xpickle' String
weightOfMaterialTag
	 ) (
		String -> PU CriterionWeight
xpickle' String
weightOfMobilityTag
	 ) (
		String -> PU CriterionWeight
xpickle' String
weightOfPieceSquareValueTag
	 ) (
		String -> PU CriterionWeight
xpickle' String
weightOfCastlingPotentialTag
	 ) (
		String -> PU CriterionWeight
xpickle' String
weightOfDefenceTag
	 ) (
		String -> PU CriterionWeight
xpickle' String
weightOfDoubledPawnsTag
	 ) (
		String -> PU CriterionWeight
xpickle' String
weightOfIsolatedPawnsTag
	 ) (
		String -> PU CriterionWeight
xpickle' String
weightOfPassedPawnsTag
	 ) where
		xpickle' :: String -> PU CriterionWeight
xpickle'	= CriterionWeight -> PU CriterionWeight -> PU CriterionWeight
forall a. Eq a => a -> PU a -> PU a
HXT.xpDefault CriterionWeight
forall a. Default a => a
Data.Default.def (PU CriterionWeight -> PU CriterionWeight)
-> (String -> PU CriterionWeight) -> String -> PU CriterionWeight
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> PU CriterionWeight -> PU CriterionWeight
forall a. String -> PU a -> PU a
`HXT.xpAttr` PU CriterionWeight
forall a. XmlPickler a => PU a
HXT.xpickle)

{- |
	* Returns the weighted sum of the specified criteria, divided by the sum of the weights; <https://www.chessprogramming.org/evaluation>

	* Each criterion increases in proportion to some desirable attribute of the proposed /game/.

	* Each criterion should be in the same range of magnitudes, so that none dominates the total, thus making the total a clear measure of the value attributed to each.

	* Also writes individual unweighted /criterion-value/s, to facilitate post-analysis; if the corresponding weight is zero, for efficiency evaluation of the criterion is avoided.
-}
calculateWeightedMean
	:: CriteriaWeights
	-> Metric.CriterionValue.CriterionValue					-- ^ /material/:	maximum if a player's /move/ equals the maximum total piece value (including /queened/ @Pawn@s), while their opponent has just a @King@.
	-> Metric.CriterionValue.CriterionValue					-- ^ /mobility/:	maximum when the opponent is check-mated.
	-> Metric.CriterionValue.CriterionValue					-- ^ /pieceSquareValue/:	maximum when this player occupies all the strategically important squares & the opponent none.
	-> Metric.CriterionValue.CriterionValue					-- ^ /castlingPotential/:	maximum when this player either has /castled/ or can, but the opponent has been permanently prevented.
	-> Metric.CriterionValue.CriterionValue					-- ^ /defence/:	maximum when this player's /piece/s are fully utilised in defence, but none of the opponent's are.
	-> Metric.CriterionValue.CriterionValue					-- ^ /doubledPawns/:	maximum when this player hasn't any /doubled/ @Pawn@s & the opponent has two files of four @Pawn@s.
	-> Metric.CriterionValue.CriterionValue					-- ^ /isolatedPawns/:	maximum when this player hasn't any /isolated/ @Pawn@s & all the opponent's @Pawn@s are /isolated/.
	-> Metric.CriterionValue.CriterionValue					-- ^ /passedPawns/:	maximum when this player has 8 /passed/ @Pawn@s & the opponent has none.
	-> Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues	-- ^ The individual /criteria/ values, & their /weighted mean/.
calculateWeightedMean :: CriteriaWeights
-> Double
-> Double
-> Double
-> Double
-> Double
-> Double
-> Double
-> Double
-> WeightedMeanAndCriterionValues
calculateWeightedMean MkCriteriaWeights {
	getWeightOfMaterial :: CriteriaWeights -> CriterionWeight
getWeightOfMaterial		= CriterionWeight
weightOfMaterial,
	getWeightOfMobility :: CriteriaWeights -> CriterionWeight
getWeightOfMobility		= CriterionWeight
weightOfMobility,
	getWeightOfPieceSquareValue :: CriteriaWeights -> CriterionWeight
getWeightOfPieceSquareValue	= CriterionWeight
weightOfPieceSquareValue,
	getWeightOfCastlingPotential :: CriteriaWeights -> CriterionWeight
getWeightOfCastlingPotential	= CriterionWeight
weightOfCastlingPotential,
	getWeightOfDefence :: CriteriaWeights -> CriterionWeight
getWeightOfDefence		= CriterionWeight
weightOfDefence,
	getWeightOfDoubledPawns :: CriteriaWeights -> CriterionWeight
getWeightOfDoubledPawns		= CriterionWeight
weightOfDoubledPawns,
	getWeightOfIsolatedPawns :: CriteriaWeights -> CriterionWeight
getWeightOfIsolatedPawns	= CriterionWeight
weightOfIsolatedPawns,
	getWeightOfPassedPawns :: CriteriaWeights -> CriterionWeight
getWeightOfPassedPawns		= CriterionWeight
weightOfPassedPawns
} Double
material Double
mobility Double
pieceSquareValue Double
castlingPotential Double
defence Double
doubledPawns Double
isolatedPawns Double
passedPawns	= [(Double, CriterionWeight)] -> WeightedMeanAndCriterionValues
Metric.WeightedMeanAndCriterionValues.calculateWeightedMean [
	(
		Double
material,		CriterionWeight
weightOfMaterial
	), (
		Double
mobility,		CriterionWeight
weightOfMobility
	), (
		Double
pieceSquareValue,	CriterionWeight
weightOfPieceSquareValue
	), (
		Double
castlingPotential,	CriterionWeight
weightOfCastlingPotential
	), (
		Double
defence,		CriterionWeight
weightOfDefence
	), (
		Double
doubledPawns,		CriterionWeight
weightOfDoubledPawns
	), (
		Double
isolatedPawns,		CriterionWeight
weightOfIsolatedPawns
	), (
		Double
passedPawns,		CriterionWeight
weightOfPassedPawns
	)
 ]

-- | The type of a function which mutates 'CriteriaWeights'.
type Transformation	= CriteriaWeights -> CriteriaWeights

-- | Adjust the mean weight, so that the maximum weight is @1@.
normalise :: Transformation
normalise :: Transformation
normalise criteriaWeights :: CriteriaWeights
criteriaWeights@MkCriteriaWeights {
	getWeightOfMaterial :: CriteriaWeights -> CriterionWeight
getWeightOfMaterial		= CriterionWeight
weightOfMaterial,
	getWeightOfMobility :: CriteriaWeights -> CriterionWeight
getWeightOfMobility		= CriterionWeight
weightOfMobility,
	getWeightOfPieceSquareValue :: CriteriaWeights -> CriterionWeight
getWeightOfPieceSquareValue	= CriterionWeight
weightOfPieceSquareValue,
	getWeightOfCastlingPotential :: CriteriaWeights -> CriterionWeight
getWeightOfCastlingPotential	= CriterionWeight
weightOfCastlingPotential,
	getWeightOfDefence :: CriteriaWeights -> CriterionWeight
getWeightOfDefence		= CriterionWeight
weightOfDefence,
	getWeightOfDoubledPawns :: CriteriaWeights -> CriterionWeight
getWeightOfDoubledPawns		= CriterionWeight
weightOfDoubledPawns,
	getWeightOfIsolatedPawns :: CriteriaWeights -> CriterionWeight
getWeightOfIsolatedPawns	= CriterionWeight
weightOfIsolatedPawns,
	getWeightOfPassedPawns :: CriteriaWeights -> CriterionWeight
getWeightOfPassedPawns		= CriterionWeight
weightOfPassedPawns
} = Bool -> Transformation
forall a. (?callStack::CallStack) => Bool -> a -> a
Control.Exception.assert (
	CriteriaWeights
criteriaWeights CriteriaWeights -> CriteriaWeights -> Bool
forall a. Eq a => a -> a -> Bool
/= CriteriaWeights
forall a. Bounded a => a
minBound	-- Guard against divide-by-zero.
 ) MkCriteriaWeights :: CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriterionWeight
-> CriteriaWeights
MkCriteriaWeights {
	getWeightOfMaterial :: CriterionWeight
getWeightOfMaterial		= CriterionWeight -> CriterionWeight
normaliseCriterionWeight CriterionWeight
weightOfMaterial,
	getWeightOfMobility :: CriterionWeight
getWeightOfMobility		= CriterionWeight -> CriterionWeight
normaliseCriterionWeight CriterionWeight
weightOfMobility,
	getWeightOfPieceSquareValue :: CriterionWeight
getWeightOfPieceSquareValue	= CriterionWeight -> CriterionWeight
normaliseCriterionWeight CriterionWeight
weightOfPieceSquareValue,
	getWeightOfCastlingPotential :: CriterionWeight
getWeightOfCastlingPotential	= CriterionWeight -> CriterionWeight
normaliseCriterionWeight CriterionWeight
weightOfCastlingPotential,
	getWeightOfDefence :: CriterionWeight
getWeightOfDefence		= CriterionWeight -> CriterionWeight
normaliseCriterionWeight CriterionWeight
weightOfDefence,
	getWeightOfDoubledPawns :: CriterionWeight
getWeightOfDoubledPawns		= CriterionWeight -> CriterionWeight
normaliseCriterionWeight CriterionWeight
weightOfDoubledPawns,
	getWeightOfIsolatedPawns :: CriterionWeight
getWeightOfIsolatedPawns	= CriterionWeight -> CriterionWeight
normaliseCriterionWeight CriterionWeight
weightOfIsolatedPawns,
	getWeightOfPassedPawns :: CriterionWeight
getWeightOfPassedPawns		= CriterionWeight -> CriterionWeight
normaliseCriterionWeight CriterionWeight
weightOfPassedPawns
 } where
	normaliseCriterionWeight :: CriterionWeight -> CriterionWeight
normaliseCriterionWeight	= (
		CriterionWeight -> CriterionWeight -> CriterionWeight
forall a. Fractional a => a -> a -> a
/ [CriterionWeight] -> CriterionWeight
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [
			CriterionWeight
weightOfMaterial,
			CriterionWeight
weightOfMobility,
			CriterionWeight
weightOfPieceSquareValue,
			CriterionWeight
weightOfCastlingPotential,
			CriterionWeight
weightOfDefence,
			CriterionWeight
weightOfDoubledPawns,
			CriterionWeight
weightOfIsolatedPawns,
			CriterionWeight
weightOfPassedPawns
		]
	 ) -- Section.