{-# LANGUAGE LambdaCase #-}
{-
	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@]

	* Itemises the various reasons for terminating a game.

	* Each reason corresponds to a rule in chess.
-}

module BishBosh.Rule.GameTerminationReason(
-- * Types
-- ** Data-types
	GameTerminationReason(),
-- * Functions
	toResult,
-- ** Constructors
	mkCheckMate,
	mkResignation,
	mkDraw,
-- ** Predicates
	isCheckMateBy,
	isCheckMate,
	isResignation,
	isDraw,
	isDrawByInsufficientMaterial,
	isStaleMate
) where

import qualified	BishBosh.Colour.LogicalColour		as Colour.LogicalColour
import qualified	BishBosh.Property.FixedMembership	as Property.FixedMembership
import qualified	BishBosh.Property.Opposable		as Property.Opposable
import qualified	BishBosh.Rule.DrawReason		as Rule.DrawReason
import qualified	BishBosh.Rule.Result			as Rule.Result
import qualified	Control.DeepSeq

-- | The sum-type of ways in which a game can legally be terminated.
data GameTerminationReason
	= CheckMateOf Colour.LogicalColour.LogicalColour	-- ^ The /logical colour/ of the /check-mated/ player.
	| ResignationBy Colour.LogicalColour.LogicalColour	-- ^ The /logical colour/ of the player who resigned.
	| Draw Rule.DrawReason.DrawReason
	deriving (GameTerminationReason -> GameTerminationReason -> Bool
(GameTerminationReason -> GameTerminationReason -> Bool)
-> (GameTerminationReason -> GameTerminationReason -> Bool)
-> Eq GameTerminationReason
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GameTerminationReason -> GameTerminationReason -> Bool
$c/= :: GameTerminationReason -> GameTerminationReason -> Bool
== :: GameTerminationReason -> GameTerminationReason -> Bool
$c== :: GameTerminationReason -> GameTerminationReason -> Bool
Eq, Eq GameTerminationReason
Eq GameTerminationReason
-> (GameTerminationReason -> GameTerminationReason -> Ordering)
-> (GameTerminationReason -> GameTerminationReason -> Bool)
-> (GameTerminationReason -> GameTerminationReason -> Bool)
-> (GameTerminationReason -> GameTerminationReason -> Bool)
-> (GameTerminationReason -> GameTerminationReason -> Bool)
-> (GameTerminationReason
    -> GameTerminationReason -> GameTerminationReason)
-> (GameTerminationReason
    -> GameTerminationReason -> GameTerminationReason)
-> Ord GameTerminationReason
GameTerminationReason -> GameTerminationReason -> Bool
GameTerminationReason -> GameTerminationReason -> Ordering
GameTerminationReason
-> GameTerminationReason -> GameTerminationReason
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: GameTerminationReason
-> GameTerminationReason -> GameTerminationReason
$cmin :: GameTerminationReason
-> GameTerminationReason -> GameTerminationReason
max :: GameTerminationReason
-> GameTerminationReason -> GameTerminationReason
$cmax :: GameTerminationReason
-> GameTerminationReason -> GameTerminationReason
>= :: GameTerminationReason -> GameTerminationReason -> Bool
$c>= :: GameTerminationReason -> GameTerminationReason -> Bool
> :: GameTerminationReason -> GameTerminationReason -> Bool
$c> :: GameTerminationReason -> GameTerminationReason -> Bool
<= :: GameTerminationReason -> GameTerminationReason -> Bool
$c<= :: GameTerminationReason -> GameTerminationReason -> Bool
< :: GameTerminationReason -> GameTerminationReason -> Bool
$c< :: GameTerminationReason -> GameTerminationReason -> Bool
compare :: GameTerminationReason -> GameTerminationReason -> Ordering
$ccompare :: GameTerminationReason -> GameTerminationReason -> Ordering
$cp1Ord :: Eq GameTerminationReason
Ord, ReadPrec [GameTerminationReason]
ReadPrec GameTerminationReason
Int -> ReadS GameTerminationReason
ReadS [GameTerminationReason]
(Int -> ReadS GameTerminationReason)
-> ReadS [GameTerminationReason]
-> ReadPrec GameTerminationReason
-> ReadPrec [GameTerminationReason]
-> Read GameTerminationReason
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [GameTerminationReason]
$creadListPrec :: ReadPrec [GameTerminationReason]
readPrec :: ReadPrec GameTerminationReason
$creadPrec :: ReadPrec GameTerminationReason
readList :: ReadS [GameTerminationReason]
$creadList :: ReadS [GameTerminationReason]
readsPrec :: Int -> ReadS GameTerminationReason
$creadsPrec :: Int -> ReadS GameTerminationReason
Read, Int -> GameTerminationReason -> ShowS
[GameTerminationReason] -> ShowS
GameTerminationReason -> String
(Int -> GameTerminationReason -> ShowS)
-> (GameTerminationReason -> String)
-> ([GameTerminationReason] -> ShowS)
-> Show GameTerminationReason
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GameTerminationReason] -> ShowS
$cshowList :: [GameTerminationReason] -> ShowS
show :: GameTerminationReason -> String
$cshow :: GameTerminationReason -> String
showsPrec :: Int -> GameTerminationReason -> ShowS
$cshowsPrec :: Int -> GameTerminationReason -> ShowS
Show)

instance Control.DeepSeq.NFData GameTerminationReason where
	rnf :: GameTerminationReason -> ()
rnf (CheckMateOf LogicalColour
logicalColour)		= LogicalColour -> ()
forall a. NFData a => a -> ()
Control.DeepSeq.rnf LogicalColour
logicalColour
	rnf (ResignationBy LogicalColour
logicalColour)	= LogicalColour -> ()
forall a. NFData a => a -> ()
Control.DeepSeq.rnf LogicalColour
logicalColour
	rnf (Draw DrawReason
drawReason)			= DrawReason -> ()
forall a. NFData a => a -> ()
Control.DeepSeq.rnf DrawReason
drawReason

instance Property.Opposable.Opposable GameTerminationReason where
	getOpposite :: GameTerminationReason -> GameTerminationReason
getOpposite (CheckMateOf LogicalColour
logicalColour)		= LogicalColour -> GameTerminationReason
CheckMateOf (LogicalColour -> GameTerminationReason)
-> LogicalColour -> GameTerminationReason
forall a b. (a -> b) -> a -> b
$ LogicalColour -> LogicalColour
forall a. Opposable a => a -> a
Property.Opposable.getOpposite LogicalColour
logicalColour
	getOpposite (ResignationBy LogicalColour
logicalColour)	= LogicalColour -> GameTerminationReason
ResignationBy (LogicalColour -> GameTerminationReason)
-> LogicalColour -> GameTerminationReason
forall a b. (a -> b) -> a -> b
$ LogicalColour -> LogicalColour
forall a. Opposable a => a -> a
Property.Opposable.getOpposite LogicalColour
logicalColour
	getOpposite GameTerminationReason
draw				= GameTerminationReason
draw

instance Property.FixedMembership.FixedMembership GameTerminationReason where
	members :: [GameTerminationReason]
members	= (LogicalColour -> GameTerminationReason)
-> [LogicalColour] -> [GameTerminationReason]
forall a b. (a -> b) -> [a] -> [b]
map LogicalColour -> GameTerminationReason
CheckMateOf [LogicalColour]
forall a. FixedMembership a => [a]
Property.FixedMembership.members [GameTerminationReason]
-> [GameTerminationReason] -> [GameTerminationReason]
forall a. [a] -> [a] -> [a]
++ (LogicalColour -> GameTerminationReason)
-> [LogicalColour] -> [GameTerminationReason]
forall a b. (a -> b) -> [a] -> [b]
map LogicalColour -> GameTerminationReason
ResignationBy [LogicalColour]
forall a. FixedMembership a => [a]
Property.FixedMembership.members [GameTerminationReason]
-> [GameTerminationReason] -> [GameTerminationReason]
forall a. [a] -> [a] -> [a]
++ (DrawReason -> GameTerminationReason)
-> [DrawReason] -> [GameTerminationReason]
forall a b. (a -> b) -> [a] -> [b]
map DrawReason -> GameTerminationReason
Draw [DrawReason]
forall a. FixedMembership a => [a]
Property.FixedMembership.members

-- | Convert to a /result/.
toResult :: GameTerminationReason -> Rule.Result.Result
toResult :: GameTerminationReason -> Result
toResult	= Result -> Result
forall a. Opposable a => a -> a
Property.Opposable.getOpposite (Result -> Result)
-> (GameTerminationReason -> Result)
-> GameTerminationReason
-> Result
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe LogicalColour -> Result
Rule.Result.mkResult (Maybe LogicalColour -> Result)
-> (GameTerminationReason -> Maybe LogicalColour)
-> GameTerminationReason
-> Result
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
	CheckMateOf LogicalColour
logicalColour	-> LogicalColour -> Maybe LogicalColour
forall a. a -> Maybe a
Just LogicalColour
logicalColour
	ResignationBy LogicalColour
logicalColour	-> LogicalColour -> Maybe LogicalColour
forall a. a -> Maybe a
Just LogicalColour
logicalColour
	Draw DrawReason
_				-> Maybe LogicalColour
forall a. Maybe a
Nothing

-- | Constructor.
mkCheckMate :: Colour.LogicalColour.LogicalColour -> GameTerminationReason
mkCheckMate :: LogicalColour -> GameTerminationReason
mkCheckMate	= LogicalColour -> GameTerminationReason
CheckMateOf

-- | Constructor.
mkResignation :: Colour.LogicalColour.LogicalColour -> GameTerminationReason
mkResignation :: LogicalColour -> GameTerminationReason
mkResignation	= LogicalColour -> GameTerminationReason
ResignationBy

-- | Constructor.
mkDraw :: Rule.DrawReason.DrawReason -> GameTerminationReason
mkDraw :: DrawReason -> GameTerminationReason
mkDraw	= DrawReason -> GameTerminationReason
Draw

-- | Whether the game was won by the specified player.
isCheckMateBy :: Colour.LogicalColour.LogicalColour -> GameTerminationReason -> Bool
isCheckMateBy :: LogicalColour -> GameTerminationReason -> Bool
isCheckMateBy LogicalColour
logicalColour (CheckMateOf LogicalColour
logicalColour')	= LogicalColour
logicalColour LogicalColour -> LogicalColour -> Bool
forall a. Eq a => a -> a -> Bool
/= LogicalColour
logicalColour'
isCheckMateBy LogicalColour
_ GameTerminationReason
_						= Bool
False

-- | Whether the game terminated in check-mate.
isCheckMate :: GameTerminationReason -> Bool
isCheckMate :: GameTerminationReason -> Bool
isCheckMate (CheckMateOf LogicalColour
_)	= Bool
True
isCheckMate GameTerminationReason
_			= Bool
False

-- | Whether the game was resigned.
isResignation :: GameTerminationReason -> Bool
isResignation :: GameTerminationReason -> Bool
isResignation (ResignationBy LogicalColour
_)	= Bool
True
isResignation GameTerminationReason
_			= Bool
False

-- | Whether the game was drawn.
isDraw :: GameTerminationReason -> Bool
isDraw :: GameTerminationReason -> Bool
isDraw (Draw DrawReason
_)	= Bool
True
isDraw GameTerminationReason
_	= Bool
False

-- | Predicate.
isDrawByInsufficientMaterial :: GameTerminationReason -> Bool
isDrawByInsufficientMaterial :: GameTerminationReason -> Bool
isDrawByInsufficientMaterial (Draw DrawReason
draw)	= DrawReason
draw DrawReason -> DrawReason -> Bool
forall a. Eq a => a -> a -> Bool
== DrawReason
Rule.DrawReason.insufficientMaterial
isDrawByInsufficientMaterial GameTerminationReason
_			= Bool
False

-- | Predicate.
isStaleMate :: GameTerminationReason -> Bool
isStaleMate :: GameTerminationReason -> Bool
isStaleMate (Draw DrawReason
draw)	= DrawReason
draw DrawReason -> DrawReason -> Bool
forall a. Eq a => a -> a -> Bool
== DrawReason
Rule.DrawReason.staleMate
isStaleMate GameTerminationReason
_		= Bool
False