Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- open System.Text.RegularExpressions
- open System.Linq
- open System
- module TitleModule =
- type GameTitle = GameTitle of string
- [<RequireQualifiedAccess>]
- type TitleEvents =
- | Start
- | Exit
- let view (GameTitle endGame) = endGame
- open TitleModule
- module EndGameModule =
- type EndGameTitle = EndGameTitle of string
- [<RequireQualifiedAccess>]
- type EndGameEvents =
- | PlayAgain
- | Exit
- let view (EndGameTitle endGame) = endGame
- module BingoModule =
- type Value = Value of int
- type Cell =
- { Value: Value
- X: int
- Y: int }
- type GameState =
- | NotFound
- | Winner of Cell seq
- type Bingo =
- { Cells: Cell list
- SelectedCells: Set<Cell>
- GameState: GameState
- Height: int
- Width: int }
- [<RequireQualifiedAccess>]
- type BingoEvents =
- | PlaceValue of X: int * Y: int * Value: Value
- | Exit
- type Generator =
- { Generate: unit -> Value }
- let generateBingo height width generator =
- let generateCells height width generator =
- seq {
- for y in [0..height - 1] do
- for x in [0..width - 1] do
- yield { Value = generator(); X = x; Y = y }
- }
- |> Seq.toList
- {
- Cells = generateCells height width generator
- SelectedCells = Set.empty
- GameState = NotFound
- Height = height
- Width = width
- }
- let private getCellByCoordinates x y cells =
- cells |> Seq.tryFind(fun { X = cx; Y = cy } -> cx = x && cy = y)
- let random = new Random()
- let generateGenerator () =
- { Generate = (fun _ -> Value (random.Next(0, 1))) }
- let private detectWin bingo =
- let isHorizontalWin =
- bingo.SelectedCells |> Seq.groupBy(fun { X = x } -> x) |> Seq.exists(snd >> Seq.length >> (=) bingo.Width)
- let isVerticalWin =
- bingo.SelectedCells |> Seq.groupBy(fun { Y = y } -> y) |> Seq.exists(snd >> Seq.length >> (=) bingo.Height)
- let xcoords = [0..bingo.Width - 1]
- let firstDiagonal = Seq.zip xcoords [0..bingo.Height - 1]
- let secondDiagonal = Seq.zip xcoords [bingo.Height - 1..-1..0]
- let isDiagonal1 =
- firstDiagonal
- |> Seq.filter (fun (x, y) -> getCellByCoordinates x y bingo.SelectedCells |> Option.isSome)
- |> Seq.length
- |> (=) (firstDiagonal |> Seq.length)
- let isDiagonal2 =
- secondDiagonal
- |> Seq.filter (fun (x, y) -> getCellByCoordinates x y bingo.SelectedCells |> Option.isSome)
- |> Seq.length
- |> (=) (secondDiagonal |> Seq.length)
- isDiagonal1 || isDiagonal2 ||
- isHorizontalWin || isVerticalWin
- let placeValue selectedValue x y bingo =
- let cell = bingo.Cells |> getCellByCoordinates x y
- match cell with
- | Some { Value = value } when value = selectedValue ->
- let selectedCell = { Value = value; X = x; Y = y }
- let newBingo = { bingo with SelectedCells = bingo.SelectedCells.Add selectedCell }
- let gameState = if detectWin newBingo then Winner [] else NotFound
- { newBingo with GameState = gameState }
- | _ -> bingo
- let view (bingo: Bingo) =
- let cellOptionToString = Option.map(fun { Value = (Value i) } -> i.ToString()) >> Option.defaultValue ""
- let isSelected x y bingo =
- bingo.SelectedCells
- |> getCellByCoordinates x y
- |> Option.isSome
- seq {
- yield seq { yield " "; yield! ([0..bingo.Height - 1] |> Seq.map(string) |> Seq.map(fun s -> s.PadLeft(4)))}
- yield seq { yield " "; yield! ([0..bingo.Height - 1] |> Seq.map(fun _ -> "____")) }
- for y in [0..bingo.Height - 1] do
- yield seq { yield y.ToString() + "|"; yield! seq {
- for x in [0..bingo.Width - 1] do
- let optionCell = (bingo.Cells |> getCellByCoordinates x y)
- let cellOptionString = optionCell |> cellOptionToString
- let cellValue =
- if isSelected x y bingo
- then ((sprintf "[%s]") cellOptionString)
- else cellOptionString
- yield cellValue
- }
- }
- }
- |> Seq.map (Seq.map (fun s -> s.PadLeft(4)) >> String.concat " ")
- |> String.concat "\n"
- module GameProcessor =
- open BingoModule
- open EndGameModule
- type CurrentGameState =
- | Title of GameTitle
- | Bingo of Bingo * Generator
- | EndGame of EndGameTitle
- | Exit
- type Events =
- | TitleEvents of TitleEvents
- | BingoEvents of BingoEvents
- | EndGameEvents of EndGameEvents
- let private applyEvent currentGameState event =
- match currentGameState, event with
- | Title _, TitleEvents titleEvents ->
- match titleEvents with
- | TitleEvents.Start ->
- let generator = generateGenerator()
- Bingo (generateBingo 5 5 generator.Generate, generator)
- | TitleEvents.Exit -> EndGame (EndGameTitle "Bye")
- | Bingo ({ GameState = (Winner cells) }, _), _ ->
- EndGame (EndGameTitle (sprintf "Well done! %A" cells))
- | Bingo (bingoModel, generator), BingoEvents bingoEvents ->
- match bingoEvents with
- | BingoEvents.PlaceValue (x, y, value) -> Bingo (bingoModel |> placeValue value x y, generator)
- | BingoEvents.Exit -> EndGame (EndGameTitle "Bye!")
- | EndGame _, EndGameEvents endGameEvent ->
- match endGameEvent with
- | EndGameEvents.PlayAgain -> Title (GameTitle "Bingo!")
- | EndGameEvents.Exit -> EndGame (EndGameTitle "Bye")
- | _ -> failwith "Impossible"
- let processEvents events currentGameState =
- events |> Seq.fold applyEvent currentGameState
- let init = Title (GameTitle "Bingo! (press 's' to start!)")
- let view = function
- | CurrentGameState.Title title -> TitleModule.view title
- | CurrentGameState.Bingo (bingo, _) -> BingoModule.view bingo
- | CurrentGameState.EndGame endGame -> EndGameModule.view endGame
- | CurrentGameState.Exit _ -> ""
- open GameProcessor
- open System.Threading
- [<EntryPoint>]
- let main _ =
- let rec untilPressed regex =
- let consoleOutput = Console.ReadLine()
- match Regex.IsMatch(consoleOutput, regex) with
- | true -> Regex.Matches(consoleOutput, regex)
- .Cast<Match>()
- .First()
- .Groups
- .Cast<Group>()
- .ToList()
- |> List.ofSeq
- |> List.map(fun x -> x.Value)
- | false -> untilPressed regex
- let isPressed char =
- let rec loop acc =
- if Console.KeyAvailable then
- loop (Console.ReadKey().KeyChar::acc)
- else acc
- loop [] |> List.exists((=) char)
- let run () =
- let rec loop state =
- printfn "%s" (state |> GameProcessor.view)
- match state with
- | CurrentGameState.EndGame _ ->
- Threading.Thread.Sleep(1000)
- state
- | _ ->
- let events =
- seq {
- match state with
- | CurrentGameState.Title _ ->
- if isPressed 's' then yield TitleEvents (TitleEvents.Start)
- if isPressed 'x' then yield TitleEvents (TitleEvents.Exit)
- | CurrentGameState.Bingo (_, generator) ->
- let generatedValue = generator.Generate()
- printfn "%A" generatedValue
- printfn "Input coordinaes:"
- let x, y = untilPressed "(\d+) (\d+)" |> (fun m ->
- printfn "%A" m
- m.[1] |> int, m.[2] |> int)
- yield BingoEvents (BingoModule.BingoEvents.PlaceValue (x, y, generatedValue) )
- | _ -> failwith "Unknown state"
- }
- |> Seq.toList
- Thread.Sleep(1000)
- Console.Clear()
- loop (state |> GameProcessor.processEvents events)
- loop GameProcessor.init
- run () |> ignore
- 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement