diff --git a/fsharp/ygosim/src/Board.fs b/fsharp/ygosim/src/Board.fs index 1c1bee6..d473e55 100644 --- a/fsharp/ygosim/src/Board.fs +++ b/fsharp/ygosim/src/Board.fs @@ -3,7 +3,7 @@ module Board open FSharpPlus.Lens module Side = - open Card.Card + open Card.CardInstance type Side<'s> = { field: CardInstance<'s> option @@ -31,7 +31,7 @@ module Side = module Player = open Side - open Card.Card + open Card.CardInstance type PlayerState = | InGame @@ -94,11 +94,13 @@ module Board = and Board = { players: Player * Player - moment: int * Phase } + moment: int * Phase + lastInstanceId: int } module Board = let inline players f board = f board.players <&> fun v -> { board with players = v } let inline moment f board = f board.moment <&> fun v -> { board with moment = v } + let inline lastInstanceId f board = f board.lastInstanceId <&> fun v -> { board with lastInstanceId = v } let inline turn f board = (moment << _1) f board let inline phase f board = (moment << _2) f board @@ -113,13 +115,14 @@ module Board = let inline currentPlayerHand f board = (currentPlayer << Player.hand) f board let inline currentPlayerLastNormalSummon f board = (currentPlayer << Player.lastNormalSummon) f board let inline currentPlayerMonsters f board = (currentPlayer << Player.monsters) f board + let inline currentPlayerSide f board = (currentPlayer << Player.side) f board let inline firstPlayer f board = (players << _1) f board let inline secondPlayer f board = (players << _2) f board type Card = Card.Card - type CardInstance = Card.CardInstance + type CardInstance = CardInstance.CardInstance type Monster = Card.Monster @@ -131,28 +134,52 @@ module Board = let emptyBoard = { players = (initialPlayer 8000 0, initialPlayer 8000 1) - moment = 0, Draw } + moment = 0, Draw + lastInstanceId = -1 } + + let instantiate board card = + let instance = + { CardInstance.template = card + CardInstance.id = board.lastInstanceId } + + (instance, over Board.lastInstanceId <| (+) 1 <| board) module Client = open Player open Turn + open Board + open Utils type Log = | CardToHand of string + | MonsterSummoned of Monster * int | NewPhase of Phase | StateChanged of PlayerState * PlayerState | ChooseZone of int list + | ChooseMonster of Monster list type Client = Log -> int let rec chooseZone client free = - let freeIndices = List.mapi (fun i _ -> i) free - let command = ChooseZone freeIndices - let result = client command + let result = + free + |> List.toIndices + |> ChooseZone + |> client - if List.contains result freeIndices then free.[result] + if List.containsIndex result free then result else chooseZone client free + let rec chooseMonster client monsters = + let result = + monsters + |> List.map (fun (m, _) -> m) + |> ChooseMonster + |> client + + if List.containsIndex result monsters then monsters.[result] + else chooseMonster client monsters + module Zone = open Player open Side @@ -166,13 +193,16 @@ module Zone = module Summon = open Card.Card + open Card.Monster + open Card.CardInstance open Card open Board open Zone open Client + open Utils module Normal = - let inline numberOfTributes (monster: Monster) = + let numberOfTributes (monster: Monster) = let level = monster ^. Card.level if level <= 4 then 0 @@ -191,23 +221,45 @@ module Summon = requiredTributes <= possibleTributes && freeZones > 0 - - let hasNormalSummonableMonster board = + let normalSummonable board = let hand = board ^. Board.currentPlayerHand let monsters = List.choose monster hand - List.exists <| isNormalSummonable board <| monsters + let isSummonable = view _1 >> isNormalSummonable board + + List.filter isSummonable monsters + + let hasNormalSummonableMonster = + (normalSummonable + >> List.length + >> (<=) 1) let canNormalSummon board = hasNormalSummonableMonster board && board ^. Board.currentPlayerLastNormalSummon < board ^. Board.turn let performNormalSummon client board = + let summonable = normalSummonable board + let target = chooseMonster client summonable + let (_, _id) = target + let free = freeMonsterZones <| board ^. Board.currentPlayer let zone = chooseZone client free let turn = board ^. Board.turn - board |> Board.currentPlayerLastNormalSummon .-> turn + let summonedInstance = + target + |> toCardInstance + |> Some + + let removeTarget = List.filter (fun card -> card.id <> _id) + + client <| MonsterSummoned(target ^. _1, zone) |> ignore + + board + |> over Board.currentPlayerHand removeTarget + |> (Board.currentPlayerMonsters << Lens.indexToLens zone) .-> summonedInstance + |> Board.currentPlayerLastNormalSummon .-> turn module Game = open Turn @@ -291,5 +343,7 @@ module Game = if currentState <> InGame then let newStates = getPlayerStates newBoard client <| StateChanged newStates |> ignore + + newBoard else game <| switchPhases client newBoard <| client diff --git a/fsharp/ygosim/src/Card.fs b/fsharp/ygosim/src/Card.fs index 392d540..a6f27a7 100644 --- a/fsharp/ygosim/src/Card.fs +++ b/fsharp/ygosim/src/Card.fs @@ -130,11 +130,14 @@ module Card = let inline level f card = (_2 << MonsterCardDetails.level) f card + +module CardInstance = + open Card + type CardInstance<'s> = { template: Card<'s> id: int } - module CardInstance = let inline template f card = f card.template <&> fun v -> { card with template = v } let inline _id f card = f card.id <&> fun v -> { card with id = v } @@ -142,6 +145,7 @@ module Card = module Monster = open Card + open CardInstance let monster card: option * int> = match card.template with diff --git a/fsharp/ygosim/src/Program.fs b/fsharp/ygosim/src/Program.fs index fcd9e47..1c2bf04 100644 --- a/fsharp/ygosim/src/Program.fs +++ b/fsharp/ygosim/src/Program.fs @@ -14,7 +14,7 @@ [] let main _ = - let sampleCard = + let sampleCardTemplate = Monster ({ name= "sampleCard" text="something" effects = []} @@ -24,8 +24,10 @@ attribute = Fire race = Warrior }) - - let board = over Board.secondPlayer <| toDeckBottom sampleCard <| emptyBoard + + let (sampleCard, initialBoard) = instantiate emptyBoard sampleCardTemplate + + let board = over Board.firstPlayer <| toDeckBottom sampleCard <| initialBoard let client action = match action with @@ -41,11 +43,20 @@ let i = System.Console.ReadLine() |> int free.[i] + | ChooseMonster monsters -> + printfn "What monster do you want to choose? %A" <| List.map (fun (_base, details) -> _base.name) monsters + let i = System.Console.ReadLine() |> int + + i + | MonsterSummoned (card, zone) -> + printfn "Monster %A was summoned in zone %i" card zone + 0 | _ -> printfn "Something unkown happened" 0 - game board client + let finalBoard = game board client + printfn "The final baord was: %A" finalBoard 0 // return integer code