goatee-0.3.1.1: A monadic take on a 2,500-year-old board game - library.

Safe HaskellNone
LanguageHaskell98

Game.Goatee.Lib.Monad

Contents

Description

A monad for working with game trees.

Synopsis

The Go monad

class (Functor go, Applicative go, Monad go) => MonadGo go where Source

A monad (transformer) for navigating and mutating Cursors, and remembering previous locations. See GoT and GoM.

The monad supports handlers for events raised during actions it takes, such as navigating through the tree and modifying nodes.

Methods

getCursor :: go Cursor Source

Returns the current cursor.

getCoordState :: Coord -> go CoordState Source

Returns the CoordState at the given point.

goUp :: go Bool Source

Navigates up to the parent node, fires a navigationEvent, then returns true. If already at the root of the tree, then none of this happens and false is returned.

goDown :: Int -> go Bool Source

Navigates down the tree to the child with the given index, fires a navigationEvent, then returns true. If the requested child doesn't exist, then none of this happens and false is returned.

goLeft :: go Bool Source

If possible, moves to the sibling node immediately to the left of the current one. Returns whether a move was made (i.e. whether there was a left sibling). Fires navigationEvents while moving.

goRight :: go Bool Source

If possible, moves to the sibling node immediately to the right of the current one. Returns whether a move was made (i.e. whether there was a right sibling). Fires navigationEvents while moving.

goToRoot :: go () Source

Navigates up to the root of the tree. Fires navigationEvents for each step.

goToGameInfoNode Source

Arguments

:: Bool

When no node with game info is found, then if false, return to the original node, otherwise finish at the root node.

-> go Bool 

Navigates up the tree to the node containing game info properties, if any. Returns true if a game info node was found.

pushPosition :: go () Source

Pushes the current location in the game tree onto an internal position stack, such that popPosition is capable of navigating back to the same position, even if the game tree has been modified (though the old position must still exist in the tree to return to it).

popPosition :: go () Source

Returns to the last position pushed onto the internal position stack via pushPosition. This action must be balanced by a pushPosition.

dropPosition :: go () Source

Drops the last position pushed onto the internal stack by pushPosition off of the stack. This action must be balanced by a pushPosition.

getProperties :: go [Property] Source

Returns the set of properties on the current node.

modifyProperties :: ([Property] -> [Property]) -> go () Source

Modifies the set of properties on the current node. Fires propertiesModifiedEvent after modifying if the new property set is different from the old property set (order is irrelevant).

getProperty :: Descriptor d => d -> go (Maybe Property) Source

Searches for a property on the current node, returning it if found.

getPropertyValue :: ValuedDescriptor v d => d -> go (Maybe v) Source

Searches for a valued property on the current node, returning its value if found.

putProperty :: Property -> go () Source

Sets a property on the current node, replacing an existing property with the same name, if one exists. Fires propertiesModifiedEvent if the property has changed.

deleteProperty :: Descriptor d => d -> go () Source

Deletes a property from the current node, if it's set, and fires propertiesModifiedEvent.

Note that although a Property is a Descriptor, giving a valued Property here will not cause deletion to match on the value of the property. That is, the following code will result in Nothing, because the deletion only cares about the name of the property.

do putProperty $ PL Black
   deleteProperty $ PL White
   getPropertyValue propertyPL

modifyProperty :: Descriptor d => d -> (Maybe Property -> Maybe Property) -> go () Source

Calls the given function to modify the state of the given property (descriptor) on the current node. Nothing represents the property not existing on the node, and a Just marks the property's presence. Fires propertiesModifiedEvent if the property changed. This function does not do any validation to check that the resulting tree state is valid.

modifyPropertyValue :: ValuedDescriptor v d => d -> (Maybe v -> Maybe v) -> go () Source

Calls the given function to modify the state of the given valued property (descriptor) on the current node. Nothing represents the property not existing on the node, and a Just with the property's value marks the property's presence. Fires propertiesModifiedEvent if the property changed. This function does not do any validation to check that the resulting tree state is valid.

modifyPropertyString :: (Stringlike s, ValuedDescriptor s d) => d -> (String -> String) -> go () Source

Mutates the string-valued property attached to the current node according to the given function. The input string will be empty if the current node either has the property with an empty value, or doesn't have the property. Returning an empty string removes the property from the node, if it was set. Fires propertiesModifiedEvent if the property changed.

modifyPropertyList :: ValuedDescriptor [v] d => d -> ([v] -> [v]) -> go () Source

Mutates the list-valued property attached to the current node according to the given function. The input list will be empty if the current node either has the property with an empty value, or doesn't have the property. Returning an empty list removes the property from the node, if it was set.

Fires propertiesModifiedEvent if the property changed.

See also modifyPropertyCoords.

modifyPropertyCoords :: ValuedDescriptor CoordList d => d -> ([Coord] -> [Coord]) -> go () Source

Mutates the CoordList-valued property attached to the current node according to the given function. Conversion between CoordList and [Coord] is performed automatically. The input list will be empty if the current node either has the property with an empty value, or doesn't have the property. Returning an empty list removes the property from the node, if it was set.

Importantly, this might not be specific enough for properties such as DD and VW where a present, empty list has different semantics from the property not being present. In that case, modifyPropertyValue is better.

Fires propertiesModifiedEvent if the property changed.

modifyGameInfo :: (GameInfo -> GameInfo) -> go GameInfo Source

Mutates the game info for the current path, returning the new info. If the current node or one of its ancestors has game info properties, then that node is modified. Otherwise, properties are inserted on the root node.

modifyVariationMode :: (VariationMode -> VariationMode) -> go () Source

Sets the game's VariationMode via the ST property on the root node, then fires a variationModeChangedEvent if the variation mode has changed.

getAssignedStone :: Coord -> go (Maybe (Maybe Color)) Source

Retrieves the stone assigned in the current node to a point by AB, AE, or AW. The possible results are:

  • Nothing: No stone has been assigned to the point. The point could still be in any state, e.g. from a play on the current node or some property in an ancestor node.
  • Just Nothing: The point has been assigned to be empty.
  • Just (Just Color): The point has been assigned to have a stone of the given color.

getAllAssignedStones :: go (Map Coord (Maybe Color)) Source

Looks up all stones that are assigned by AB, AE, or AW properties on the current node. Returns a map from each point to the stone that is assigned to the point.

modifyAssignedStones :: [Coord] -> (Maybe (Maybe Color) -> Maybe (Maybe Color)) -> go () Source

Modifies the state of currently assigned stones, keeping in mind that it is invalid to mix MoveProperty and SetupProperty properties in a single node. This function has the behaviour of a user changing stone assignments in a UI. How this function works is:

  • Pick a node to work with. If there is a move property on the current node and there is not already a setup property on the current node, then we'll create and modify a new child node. Otherwise, either there are no move properties on the node (so we can add setup properties at will), or there are both move and setup properties on the node (the node is already invalid), so we'll just modify the current node.
  • If we're modifying the current node, then apply the modification function to the state of stone assignment for each coordinate. See getAssignedStone for the meaning of Maybe (Maybe Color). Modify the properties in the node as necessary to apply the result (propertiesModifiedEvent). (NOTE: Currently one event is fired for each property modified; this may change in the future.)
  • If we need to create a child node, then apply the modification function to Nothing to determine if we're actually adding assignments. If the function returns a Just, then we create a child node with the necessary assignment properties, insert it (childAddedEvent), then navigate to it (navigationEvent). If the function returns Nothing, then modifyAssignedStones does nothing.

getMark :: Coord -> go (Maybe Mark) Source

Returns the Mark at a point on the current node.

modifyMark :: (Maybe Mark -> Maybe Mark) -> Coord -> go () Source

Calls the given function to modify the presence of a Mark on the current node.

addChild :: Node -> go () Source

Adds a child node to the current node at the end of the current node's child list. Fires a childAddedEvent after the child is added.

addChildAt :: Int -> Node -> go () Source

Adds a child node to the current node at the given index, shifting all existing children at and after the index to the right. The index must be in the range [0, numberOfChildren]. Fires a childAddedEvent after the child is added.

deleteChildAt :: Int -> go NodeDeleteResult Source

Tries to remove the child node at the given index below the current node. Returns a status code indicating whether the deletion succeeded, or why not.

on :: Event go h -> h -> go () Source

Registers a new event handler for a given event type.

on0 :: Event go h -> go () -> go () Source

Registers a new event handler for a given event type. Unlike on, whose handler may receive arguments, the handler given here doesn't receive any arguments.

Instances

Monad m => MonadGo (GoT m) 

data GoT m a Source

The standard monad transformer for MonadGo.

Instances

MonadTrans GoT 
MonadState s m => MonadState s (GoT m) 
MonadWriter w m => MonadWriter w (GoT m) 
Monad m => Monad (GoT m) 
Monad m => Functor (GoT m) 
Monad m => Applicative (GoT m) 
MonadIO m => MonadIO (GoT m) 
Monad m => MonadGo (GoT m) 

type GoM = GoT Identity Source

The standard monad for MonadGo.

runGoT :: Monad m => GoT m a -> Cursor -> m (a, Cursor) Source

Executes a Go monad transformer on a cursor, returning in the underlying monad a tuple that contains the resulting value and the final cursor.

runGo :: GoM a -> Cursor -> (a, Cursor) Source

Runs a Go monad on a cursor. See runGoT.

evalGoT :: Monad m => GoT m a -> Cursor -> m a Source

Executes a Go monad transformer on a cursor, returning in the underlying monad the value in the transformer.

evalGo :: GoM a -> Cursor -> a Source

Runs a Go monad on a cursor and returns the value in the monad.

execGoT :: Monad m => GoT m a -> Cursor -> m Cursor Source

Executes a Go monad transformer on a cursor, returning in the underlying monad the final cursor.

execGo :: GoM a -> Cursor -> Cursor Source

Runs a Go monad on a cursor and returns the final cursor.

data Step Source

A single step along a game tree. Either up or down.

Constructors

GoUp Int

Represents a step up from a child with the given index.

GoDown Int

Represents a step down to the child with the given index.

Instances

data NodeDeleteResult Source

The result of deleting a node.

Constructors

NodeDeleteOk

The node was deleted successfully.

NodeDeleteBadIndex

The node couldn't be deleted, because an invalid index was given.

NodeDeleteOnPathStack

The node couldn't be deleted, because it is on the path stack.

Event handling

data Event go h Source

A type of event in a Go monad that can be handled by executing an action. go is the type of the Go monad. h is the handler type, a function that takes some arguments relating to the event and returns an action in the Go monad. The arguments to the handler are usually things that would be difficult to recover from the state of the monad alone, for example the Step associated with a navigationEvent.

The Eq, Ord, and Show instances use events' names, via eventName.

Instances

Eq (Event go h) 
Ord (Event go h) 
Show (Event go h) 

data AnyEvent go Source

An existential type for any event in a particular Go monad. Like Event, the Eq, Ord, and Show instances use events' names, via eventName.

Constructors

forall h . AnyEvent (Event go h) 

Instances

Eq (AnyEvent go) 
Ord (AnyEvent go) 
Show (AnyEvent go) 

fire :: Monad m => Event (GoT m) h -> (h -> GoT m ()) -> GoT m () Source

Fires all of the handlers for the given event, using the given function to create a Go action from each of the handlers (normally themselves functions that create Go actions, if they're not just Go actions directly, depending on the event).

eventHandlerFromAction :: Event go h -> go () -> h Source

Events

childAddedEvent :: Event go (ChildAddedHandler go) Source

An event corresponding to a child node being added to the current node.

type ChildAddedHandler go = Int -> go () Source

A handler for childAddedEvents. Called with the index of the child added to the current node.

childDeletedEvent :: Event go (ChildDeletedHandler go) Source

An event corresponding to the deletion of one of the current node's children.

type ChildDeletedHandler go = Cursor -> go () Source

A handler for childDeletedEvents. It is called with a cursor at the child that was deleted (this cursor is now out of date).

gameInfoChangedEvent :: Event go (GameInfoChangedHandler go) Source

An event that is fired when the current game info changes, either by navigating past a node with game info properties, or by modifying the current game info properties.

type GameInfoChangedHandler go = GameInfo -> GameInfo -> go () Source

A handler for gameInfoChangedEvents. It is called with the old game info then the new game info.

navigationEvent :: Event go (NavigationHandler go) Source

An event that is fired when a single step up or down in a game tree is made.

type NavigationHandler go = Step -> go () Source

A handler for navigationEvents.

A navigation handler may navigate further, but beware infinite recursion. A navigation handler must end on the same node on which it started.

propertiesModifiedEvent :: Event go (PropertiesModifiedHandler go) Source

An event corresponding to a modification to the properties list of the current node.

type PropertiesModifiedHandler go = [Property] -> [Property] -> go () Source

A handler for propertiesModifiedEvents. It is called with the old property list then the new property list.

variationModeChangedEvent :: Event go (VariationModeChangedHandler go) Source

An event corresponding to a change in the active VariationMode. This can happen when modifying the ST property, and also when navigating between collections (as they have different root nodes).

type VariationModeChangedHandler go = VariationMode -> VariationMode -> go () Source

A handler for variationModeChangedEvents. It is called with the old variation mode then the new variation mode.