<commit_before>{-# LANGUAGE ExistentialQuantification #-}
module Jakway.Blackjack.Game where

import Jakway.Blackjack.Cards
import Jakway.Blackjack.CardOps
import Jakway.Blackjack.AI
import Jakway.Blackjack.Result
import Jakway.Blackjack.Visibility
import Jakway.Blackjack.Points
import Jakway.Blackjack.Match
import Control.Monad.State
import Data.Ord
import Data.Monoid
import Data.Maybe (fromJust)
import System.Random

blackjack :: [Card] -> Bool
blackjack hand = 2 == length hand && hasAce && hasFaceCard
  where
    handHas = hasCard hand
    hasAce = handHas Ace
    faceCards = Card <$> allSuits <*> [Jack, Queen, King]
    hasFaceCard = any (handHas . cardValue) faceCards
    
startingHand :: Blackjack Hand
startingHand = do
  firstCard <- Hidden <$> drawCard
  secondCard <- Shown <$> drawCard
  return [firstCard, secondCard]

foldFnSt ai = startingHand >>= play' ai

-- |Plays a game and returns the relevant state
-- |returns a tuple of (dealersHand, playerHands, playerResults)
-- |dealer score record is redundant and not returned (just the opposite of
-- every Result)
evalGame :: AI -> [AI] -> Deck -> Maybe (Match)
evalGame dealerAI [] deck = Nothing
evalGame dealerAI allPlayers deck = flip evalState deck $ do
  dealersStartingHand <- startingHand

  xdeck <- get
  let accumPlays = foldr (\thisAIProc (currDeck, allHands)) (xdeck, [dealersStartingHand]) (map foldFnSt allPlayers)

  playerHands <- reverse <$> mapM foldFnSt allPlayers
  dealerHand <- play' dealerAI dealersStartingHand
  let results = reverse . map (whoWon' dealerHand)
  return . Just $ Match dealerHand playerIDs playerHands (results playerHands)
  where playerIDs = [1.. (length allPlayers)]

playWithOtherHands :: a -> (Deck, [Hand]) -> (Deck, [Hand])
playWithOtherHands [] (deck, otherHands) = (deck, otherHands)
-- ^if we've gone through every AI we're done
playWithOtherHands aiProcs (deck, otherHands) = flip evalState deck $ do
    result <- thisAIProc hands 
    return $ reverse $ result `mconcat` otherHands

    where thisAIProc = head aiProcs
    


infixl 8 &&&
(&&&) :: forall t t1 t2. (t2 -> t) -> (t2 -> t1) -> t2 -> (t, t1)
(f &&& g) a = (f a, g a)

first :: (a -> b) -> (a, c) -> (b, c)
first f (a, b) = (f a, b)

both :: (a -> b) -> (a, a) -> (b, b)
both f (a, b) = (f a, f b)

play' :: AI -> -> Hand -> [Hand] -> Blackjack Hand
play' ai hand otherHands = do
  deck <- get
  let (resultingHand, resDeck) = play ai otherHands hand deck
  put resDeck
  return resultingHand


-- |first result in the tuple = result for the first Hand
-- |second result in the tuple = result for the second Hand
-- this function is very repetitive--rewrite it to pass a tuple of Hands
-- instead of each players hand as a separate variable
-- so it'll be:
-- whoWon :: (Hand, Hand) -> (Result, Result)
whoWon :: Hand -> Hand -> (Result, Result)
whoWon firstPlayerHand secondPlayerHand 
  --if both the dealer and a player
  --bust, it's a tie
  | firstPlayerBusted && secondPlayerBusted = (Tie, Tie)
  --check if one player busted and
  --the other didn't
  | firstPlayerBusted && not secondPlayerBusted = (Lose, Win)
  | not firstPlayerBusted && secondPlayerBusted = (Win, Lose)
  --if neither player busted, highest
  --score wins
  | firstPlayerScore == secondPlayerScore = (Tie, Tie)
  | firstPlayerScore > secondPlayerScore = (Win, Lose)
  | firstPlayerScore < secondPlayerScore = (Lose, Win)
  
  --any way to rewrite this in applicative
  --syntax?
<commit_msg>fixed syntax errors, now have to deal with type errors<commit_after>{-# LANGUAGE ExistentialQuantification #-}
module Jakway.Blackjack.Game where

import Jakway.Blackjack.Cards
import Jakway.Blackjack.CardOps
import Jakway.Blackjack.AI
import Jakway.Blackjack.Result
import Jakway.Blackjack.Visibility
import Jakway.Blackjack.Points
import Jakway.Blackjack.Match
import Control.Monad.State
import Data.Ord
import Data.Monoid
import Data.Maybe (fromJust)
import System.Random

blackjack :: [Card] -> Bool
blackjack hand = 2 == length hand && hasAce && hasFaceCard
  where
    handHas = hasCard hand
    hasAce = handHas Ace
    faceCards = Card <$> allSuits <*> [Jack, Queen, King]
    hasFaceCard = any (handHas . cardValue) faceCards
    
startingHand :: Blackjack Hand
startingHand = do
  firstCard <- Hidden <$> drawCard
  secondCard <- Shown <$> drawCard
  return [firstCard, secondCard]

foldFnSt ai = startingHand >>= play' ai

-- |Plays a game and returns the relevant state
-- |returns a tuple of (dealersHand, playerHands, playerResults)
-- |dealer score record is redundant and not returned (just the opposite of
-- every Result)
evalGame :: AI -> [AI] -> Deck -> Maybe (Match)
evalGame dealerAI [] deck = Nothing
evalGame dealerAI allPlayers deck = flip evalState deck $ do
  dealersStartingHand <- startingHand
  xdeck <- get
  let accumPlays = foldr (\thisAIProc (currDeck, allHands) -> undefined) (xdeck, [dealersStartingHand]) (map foldFnSt allPlayers)

  playerHands <- reverse <$> mapM foldFnSt allPlayers
  dealerHand <- play' dealerAI dealersStartingHand
  let results = reverse . map (whoWon' dealerHand)
  return . Just $ Match dealerHand playerIDs playerHands (results playerHands)
  where playerIDs = [1.. (length allPlayers)]

playWithOtherHands :: a -> (Deck, [Hand]) -> (Deck, [Hand])
playWithOtherHands [] (deck, otherHands) = (deck, otherHands)
-- ^if we've gone through every AI we're done
playWithOtherHands aiProcs (deck, otherHands) = flip evalState deck $ do
    result <- thisAIProc otherHands 
    return $ reverse $ result `mconcat` otherHands

    where thisAIProc = head aiProcs
    


infixl 8 &&&
(&&&) :: forall t t1 t2. (t2 -> t) -> (t2 -> t1) -> t2 -> (t, t1)
(f &&& g) a = (f a, g a)

first :: (a -> b) -> (a, c) -> (b, c)
first f (a, b) = (f a, b)

both :: (a -> b) -> (a, a) -> (b, b)
both f (a, b) = (f a, f b)

play' :: AI -> Hand -> [Hand] -> Blackjack Hand
play' ai hand otherHands = do
  deck <- get
  let (resultingHand, resDeck) = play ai otherHands hand deck
  put resDeck
  return resultingHand


-- |first result in the tuple = result for the first Hand
-- |second result in the tuple = result for the second Hand
-- this function is very repetitive--rewrite it to pass a tuple of Hands
-- instead of each players hand as a separate variable
-- so it'll be:
-- whoWon :: (Hand, Hand) -> (Result, Result)
whoWon :: Hand -> Hand -> (Result, Result)
whoWon firstPlayerHand secondPlayerHand 
  --if both the dealer and a player
  --bust, it's a tie
  | firstPlayerBusted && secondPlayerBusted = (Tie, Tie)
  --check if one player busted and
  --the other didn't
  | firstPlayerBusted && not secondPlayerBusted = (Lose, Win)
  | not firstPlayerBusted && secondPlayerBusted = (Win, Lose)
  --if neither player busted, highest
  --score wins
  | firstPlayerScore == secondPlayerScore = (Tie, Tie)
  | firstPlayerScore > secondPlayerScore = (Win, Lose)
  | firstPlayerScore < secondPlayerScore = (Lose, Win)
  
  --any way to rewrite this in applicative
  --syntax?

{'fraction_non_alphanumeric': 0.11659257134662268, 'fraction_numerical': 0.00286820593718629, 'mean_word_length': 3.705802968960864, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1181282', 'n_tokens_mistral': 2320, 'n_tokens_neox': 2236, 'n_words': 808}