evalGameTree :: Tree GameNode -> Int
evalGameTree (Node _ childTrees) =
        -- Takes children nodes and evaluates them using the negamax with
        -- alpha-beta pruning optimisation, then take the column of the best
        -- option.
        snd . iterateChildren (-pseudoInf) pseudoInf (-pseudoInf, 0)
            $ childTrees
    where -- Leaf node. Return the evaluation of this node using the
          -- 'winning rows' method.
          evalGameTree' (Node (GN board _ pl _) []) _ _ =
            evaluate pl 1 (-1) board
          -- Internal node. Evaluate children and get the best rating.
          evalGameTree' (Node _ childTrees) alpha beta =
            fst . iterateChildren alpha beta (-pseudoInf, 0) $ childTrees
          -- Evaluate children nodes using depth-first search.
          -- No remaining children. Return the data of the best child
          -- (rating and column).
          iterateChildren _     _    best [] = best
          -- There are children remaining. Calculate new alpha value, new best
          -- child and check pruning case.
          iterateChildren alpha beta (bestRating, bestCol) (t:ts) =
            let childValue = -(evalGameTree' t (-beta) (-alpha))
                newBestRat = max bestRating childValue
                newAlpha   = max alpha childValue
                newBestCol = if newBestRat > bestRating 
                                then gnColumn . rootLabel $ t
                                else bestCol
                newBest    = (newBestRat, newBestCol)
            in  if newAlpha >= beta
                    then newBest
                    else iterateChildren newAlpha beta newBest ts
          pseudoInf = 1000000

-- |The exported strategy.
evalGameTree :: Tree GameNode -> Int
evalGameTree (Node _ childTrees) =
        -- Takes children nodes and evaluates them using the negamax with
        -- alpha-beta pruning optimisation, then take the column of the best
        -- option.
        snd . iterateChildren (-pseudoInf) pseudoInf (-pseudoInf, 0)
            $ childTrees
    where -- Leaf node. Return the evaluation of this node using the
          -- 'winning rows' method.
          evalGameTree' (Node (GN board _ pl _) []) _ _ =
            evaluate pl 1 (-1) board
          -- Internal node. Evaluate children and get the best rating.
          evalGameTree' (Node _ childTrees) alpha beta =
            fst . iterateChildren alpha beta (-pseudoInf, 0) $ childTrees
          -- Evaluate children nodes using depth-first search.
          -- No remaining children. Return the data of the best child
          -- (rating and column).
          iterateChildren _     _    best [] = best
          -- There are children remaining. Calculate new alpha value, new best
          -- child and check pruning case.
          iterateChildren alpha beta (bestRating, bestCol) (t:ts) =
            let childValue = -(evalGameTree' t (-beta) (-alpha))
                newBestRat = max bestRating childValue
                newAlpha   = max alpha childValue
                newBestCol = if newBestRat > bestRating 
                                then gnColumn . rootLabel $ t
                                else bestCol
                newBest    = (newBestRat, newBestCol)
            in  if newAlpha >= beta
                    then newBest
                    else iterateChildren newAlpha beta newBest ts
          pseudoInf = 1000000

-- |The exported strategy.
evalGameTree (Node _ childTrees) =
        -- Takes children nodes and evaluates them using the negamax with
        -- alpha-beta pruning optimisation, then take the column of the best
        -- option.
        snd . iterateChildren (-pseudoInf) pseudoInf (-pseudoInf, 0)
            $ childTrees
    where -- Leaf node. Return the evaluation of this node using the
          -- 'winning rows' method.
          evalGameTree' (Node (GN board _ pl _) []) _ _ =
            evaluate pl 1 (-1) board
          -- Internal node. Evaluate children and get the best rating.
          evalGameTree' (Node _ childTrees) alpha beta =
            fst . iterateChildren alpha beta (-pseudoInf, 0) $ childTrees
          -- Evaluate children nodes using depth-first search.
          -- No remaining children. Return the data of the best child
          -- (rating and column).
          iterateChildren _     _    best [] = best
          -- There are children remaining. Calculate new alpha value, new best
          -- child and check pruning case.
          iterateChildren alpha beta (bestRating, bestCol) (t:ts) =
            let childValue = -(evalGameTree' t (-beta) (-alpha))
                newBestRat = max bestRating childValue
                newAlpha   = max alpha childValue
                newBestCol = if newBestRat > bestRating 
                                then gnColumn . rootLabel $ t
                                else bestCol
                newBest    = (newBestRat, newBestCol)
            in  if newAlpha >= beta
                    then newBest
                    else iterateChildren newAlpha beta newBest ts
          pseudoInf = 1000000

-- |The exported strategy.