diff --git a/fsharp/ygosim/AdobeAIRInstaller.bin b/fsharp/ygosim/AdobeAIRInstaller.bin new file mode 100755 index 0000000..afbdc28 Binary files /dev/null and b/fsharp/ygosim/AdobeAIRInstaller.bin differ diff --git a/fsharp/ygosim/src/Board.fs b/fsharp/ygosim/src/Board.fs index d473e55..61820e9 100644 --- a/fsharp/ygosim/src/Board.fs +++ b/fsharp/ygosim/src/Board.fs @@ -1,6 +1,7 @@ module Board open FSharpPlus.Lens +open FSharpPlus.Operators module Side = open Card.CardInstance @@ -124,7 +125,9 @@ module Board = type CardInstance = CardInstance.CardInstance - type Monster = Card.Monster + type Monster = MonsterTypes.Monster + + type MonsterInstance = MonsterInstance.MonsterInstance type Effect = Effect.Effect @@ -147,9 +150,11 @@ module Board = module Client = open Player open Turn + open Card open Board open Utils + type Log = | CardToHand of string | MonsterSummoned of Monster * int @@ -157,35 +162,57 @@ module Client = | StateChanged of PlayerState * PlayerState | ChooseZone of int list | ChooseMonster of Monster list + | ChooseTributes of Monster list type Client = Log -> int let rec chooseZone client free = let result = - free - |> List.toIndices + free |>> view _1 |> ChooseZone |> client - if List.containsIndex result free then result + if List.containsIndex result free then free.[result] ^. _1 else chooseZone client free let rec chooseMonster client monsters = let result = monsters - |> List.map (fun (m, _) -> m) + |> List.map (view _1) |> ChooseMonster |> client if List.containsIndex result monsters then monsters.[result] else chooseMonster client monsters + let rec chooseTributes client monsters count old: list = + match count with + | 0 -> old + | count -> + let resultIndex = + monsters + |> map (view _1) + |> ChooseTributes + |> client + + if List.containsIndex resultIndex monsters then + let result = monsters.[resultIndex] + let withoutCurrent = filter <| Card.MonsterInstance.withoutInstance result <| monsters + chooseTributes client withoutCurrent <| count - 1 <| result :: old + else + chooseTributes client monsters count old + + module Zone = open Player open Side open Board - let freeMonsterZones (player: Player) = List.filter Option.isNone player.side.monsters + let freeMonsterZones (player: Player) = + player.side.monsters + |> List.indexed + |> List.filter (view _2 >> Option.isNone) + let freeMonsterZoneCount = freeMonsterZones >> List.length let hasFreeMonsterZones = (>=) << freeMonsterZoneCount let hasFreeMonsterZone player = hasFreeMonsterZones player 1 @@ -194,6 +221,7 @@ module Zone = module Summon = open Card.Card open Card.Monster + open Player open Card.CardInstance open Card open Board @@ -238,25 +266,48 @@ module Summon = hasNormalSummonableMonster board && board ^. Board.currentPlayerLastNormalSummon < board ^. Board.turn let performNormalSummon client board = + // Decide what monster to summon let summonable = normalSummonable board let target = chooseMonster client summonable - let (_, _id) = target + let (_monster, _id) = target - let free = freeMonsterZones <| board ^. Board.currentPlayer + // Find what monsters to tribute + let tributteCount = numberOfTributes _monster + let possibleTributes = board ^. Board.currentPlayerMonsters |>> ((=<<) monster) |> choose id + let tributes = chooseTributes client possibleTributes tributteCount [] + + // helpers to remove the tributes from the board + let replaceInstance instance = + let isInstance = List.tryFind (view _2 >> (=) instance.id) tributes |> Option.isSome + if isInstance then None + else Some instance + + let replaceTributes = map <| Option.bind replaceInstance + + // Tribute monsters + let boardWithoutTributes = board |> over Board.currentPlayerMonsters replaceTributes + let free = freeMonsterZones <| boardWithoutTributes ^. Board.currentPlayer + + // TODO: move tributes to graveyard + + // Choose a zone to summon the monster let zone = chooseZone client free + let turn = boardWithoutTributes ^. Board.turn - let turn = board ^. Board.turn - + // Instance to actually summon let summonedInstance = target |> toCardInstance |> Some + // Remove card from hand let removeTarget = List.filter (fun card -> card.id <> _id) + // Notify the client a new monster was summoned client <| MonsterSummoned(target ^. _1, zone) |> ignore - board + // Update the board + boardWithoutTributes |> over Board.currentPlayerHand removeTarget |> (Board.currentPlayerMonsters << Lens.indexToLens zone) .-> summonedInstance |> Board.currentPlayerLastNormalSummon .-> turn @@ -283,7 +334,7 @@ module Game = |> Board.currentPlayerHand .-> hand |> Board.currentPlayerDeck .-> deck - let toDeckBottom (card: CardInstance) (player: Player) = over Player.deck (fun d -> card :: d) player + let toDeckBottom (card: CardInstance) (player: Player) = over Player.deck (fun d -> rev <| card :: rev d) player let handleMainPhase client board = if canNormalSummon board then performNormalSummon client board diff --git a/fsharp/ygosim/src/Card.fs b/fsharp/ygosim/src/Card.fs index a6f27a7..9ec7f89 100644 --- a/fsharp/ygosim/src/Card.fs +++ b/fsharp/ygosim/src/Card.fs @@ -1,6 +1,7 @@ module Card open FSharpPlus.Lens +open FSharpPlus.Operators module Effect = type Condition<'s> = 's -> bool @@ -28,8 +29,7 @@ module Effect = let inline resolve f effect = f effect.resolve <&> fun r -> { effect with resolve = r } let inline _type f effect = f effect._type <&> fun t -> { effect with _type = t } - -module Card = +module BaseCard = open Effect type BaseCard<'s> = @@ -42,18 +42,10 @@ module Card = let inline text f card = f card.text <&> fun v -> { card with text = v } let inline effects f card = f card.effects <&> fun v -> { card with effects = v } - type SpellCardType = - | NormalSpell - | Field - | Equip - | ContinuosSpell - | QuickPlay - | Ritual - type TrapCardType = - | NormalTrap - | Counter - | ContinuosTrap +module MonsterTypes = + open BaseCard + type Attribute = | Dark @@ -91,19 +83,6 @@ module Card = | Wyrm | Zombie - type SpellCardDetails = - { spellType: SpellCardType } - - module SpellCardDetails = - let inline spellType f card = f card.spellType <&> fun v -> { card with spellType = v } - - type TrapCardDetails = - { trapType: TrapCardType } - - module TrapCardDetails = - let inline trapType f card = f card.trapType <&> fun v -> { card with trapType = v } - - type MonsterCardDetails = { attack: int defense: int @@ -117,8 +96,39 @@ module Card = let inline attribute f card = f card.attribute <&> fun v -> { card with attribute = v } let inline level f card = f card.level <&> fun v -> { card with level = v } + type Monster<'s> = BaseCard<'s> * MonsterCardDetails +module Card = + open BaseCard + open MonsterTypes + + type SpellCardType = + | NormalSpell + | Field + | Equip + | ContinuosSpell + | QuickPlay + | Ritual + + type TrapCardType = + | NormalTrap + | Counter + | ContinuosTrap + + type SpellCardDetails = + { spellType: SpellCardType } + + module SpellCardDetails = + let inline spellType f card = f card.spellType <&> fun v -> { card with spellType = v } + + type TrapCardDetails = + { trapType: TrapCardType } + + module TrapCardDetails = + let inline trapType f card = f card.trapType <&> fun v -> { card with trapType = v } + + type Card<'s> = | Monster of Monster<'s> | Spell of BaseCard<'s> * SpellCardDetails @@ -144,10 +154,11 @@ module CardInstance = module Monster = - open Card + open MonsterTypes open CardInstance + open Card - let monster card: option * int> = + let monster card: option * int> = match card.template with | Monster m -> Some(m, card.id) | _ -> None @@ -157,6 +168,20 @@ module Monster = { template = Monster card id = _id } +module MonsterInstance = + open MonsterTypes + + type MonsterInstance<'s> = Monster<'s> * int + + module private Internals = + // idk how to preperly override (=) + let areEqual (_, _id1) (_, _id2) = _id1 = _id2 + let (==) = areEqual + + open Internals + + let withoutInstance instance = areEqual instance >> not + module Decklist = type Decklist = { main: int list diff --git a/fsharp/ygosim/src/Program.fs b/fsharp/ygosim/src/Program.fs index 1c2bf04..ee6fdfa 100644 --- a/fsharp/ygosim/src/Program.fs +++ b/fsharp/ygosim/src/Program.fs @@ -5,6 +5,8 @@ open Board.Game open Board.Client open Card.Card + open Card.MonsterTypes + open Card.BaseCard let printState state = match state with @@ -24,10 +26,27 @@ attribute = Fire race = Warrior }) + let tributeCardTemplate = + Monster ({ name= "sampleCard2" + text="something" + effects = []} + ,{ attack = 3000 + defense = 2500 + level = 7 + attribute = Fire + race = Warrior }) - let (sampleCard, initialBoard) = instantiate emptyBoard sampleCardTemplate - - let board = over Board.firstPlayer <| toDeckBottom sampleCard <| initialBoard + let (sampleCard1, board1) = instantiate emptyBoard sampleCardTemplate + let (sampleCard2, board2) = instantiate board1 sampleCardTemplate + let (sampleCard3, board3) = instantiate board2 sampleCardTemplate + let (sampleCard4, board4) = instantiate board3 sampleCardTemplate + let (tributeCard, board5) = instantiate board4 tributeCardTemplate + + let board6 = over Board.firstPlayer <| toDeckBottom sampleCard1 <| board5 + let board7 = over Board.firstPlayer <| toDeckBottom sampleCard2 <| board6 + let board8 = over Board.secondPlayer <| toDeckBottom sampleCard3 <| board7 + let board9 = over Board.secondPlayer <| toDeckBottom sampleCard4 <| board8 + let board10 = over Board.firstPlayer <| toDeckBottom tributeCard <| board9 let client action = match action with @@ -40,14 +59,13 @@ 0 | ChooseZone free -> printfn "What Zone do wou want to use? %A" free - let i = System.Console.ReadLine() |> int - - free.[i] + System.Console.ReadLine() |> int | 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 + System.Console.ReadLine() |> int + | ChooseTributes monsters -> + printfn "What monster do you want to tribute? %A" <| List.map (fun (_base, details) -> _base.name) monsters + System.Console.ReadLine() |> int | MonsterSummoned (card, zone) -> printfn "Monster %A was summoned in zone %i" card zone 0 @@ -55,7 +73,7 @@ printfn "Something unkown happened" 0 - let finalBoard = game board client + let finalBoard = game board10 client printfn "The final baord was: %A" finalBoard diff --git a/fsharp/ygosim/src/Utils.fs b/fsharp/ygosim/src/Utils.fs index 74c8dff..434c539 100644 --- a/fsharp/ygosim/src/Utils.fs +++ b/fsharp/ygosim/src/Utils.fs @@ -7,8 +7,6 @@ module List = else previous) - let (.->) = setIndex - let toIndices list = List.mapi (fun i _ -> i) list let containsIndex index list = index >= 0 && index < List.length list