Advertisement
Guest User

Untitled

a guest
Mar 29th, 2019
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
F# 8.88 KB | None | 0 0
  1. open System.Text.RegularExpressions
  2. open System.Linq
  3. open System
  4.  
  5. module TitleModule =
  6.     type GameTitle = GameTitle of string
  7.        
  8.     [<RequireQualifiedAccess>]
  9.     type TitleEvents =
  10.         | Start
  11.         | Exit
  12.  
  13.     let view (GameTitle endGame) = endGame
  14.  
  15. open TitleModule
  16.  
  17. module EndGameModule =
  18.     type EndGameTitle = EndGameTitle of string
  19.  
  20.     [<RequireQualifiedAccess>]
  21.     type EndGameEvents =
  22.         | PlayAgain
  23.         | Exit
  24.  
  25.     let view (EndGameTitle endGame) = endGame
  26.  
  27. module BingoModule =
  28.     type Value = Value of int
  29.  
  30.     type Cell =
  31.         { Value: Value
  32.           X: int
  33.           Y: int }
  34.  
  35.     type GameState =
  36.         | NotFound
  37.         | Winner of Cell seq
  38.  
  39.     type Bingo =
  40.         { Cells: Cell list
  41.           SelectedCells: Set<Cell>
  42.           GameState: GameState
  43.           Height: int
  44.           Width: int }
  45.  
  46.     [<RequireQualifiedAccess>]
  47.     type BingoEvents =
  48.         | PlaceValue of X: int * Y: int * Value: Value
  49.         | Exit
  50.  
  51.     type Generator =
  52.         { Generate: unit -> Value }
  53.  
  54.     let generateBingo height width generator =
  55.         let generateCells height width generator =
  56.             seq {
  57.                 for y in [0..height - 1] do
  58.                     for x in [0..width - 1] do
  59.                         yield { Value = generator(); X = x; Y = y }
  60.             }
  61.             |> Seq.toList
  62.  
  63.         {
  64.             Cells = generateCells height width generator
  65.             SelectedCells = Set.empty
  66.             GameState = NotFound
  67.             Height = height
  68.             Width = width
  69.         }
  70.    
  71.     let private getCellByCoordinates x y cells =
  72.         cells |> Seq.tryFind(fun { X = cx; Y = cy } -> cx = x && cy = y)
  73.  
  74.     let random = new Random()
  75.  
  76.     let generateGenerator () =
  77.         { Generate = (fun _ -> Value (random.Next(0, 1))) }
  78.  
  79.     let private detectWin bingo =
  80.         let isHorizontalWin =
  81.             bingo.SelectedCells |> Seq.groupBy(fun { X = x } -> x) |> Seq.exists(snd >> Seq.length >> (=) bingo.Width)
  82.  
  83.         let isVerticalWin =
  84.             bingo.SelectedCells |> Seq.groupBy(fun { Y = y } -> y) |> Seq.exists(snd >> Seq.length >> (=) bingo.Height)
  85.  
  86.         let xcoords = [0..bingo.Width - 1]
  87.  
  88.         let firstDiagonal = Seq.zip xcoords [0..bingo.Height - 1]
  89.         let secondDiagonal = Seq.zip xcoords [bingo.Height - 1..-1..0]
  90.  
  91.         let isDiagonal1 =
  92.             firstDiagonal
  93.             |> Seq.filter (fun (x, y) -> getCellByCoordinates x y bingo.SelectedCells |> Option.isSome)
  94.             |> Seq.length
  95.             |> (=) (firstDiagonal |> Seq.length)
  96.  
  97.         let isDiagonal2 =
  98.             secondDiagonal
  99.             |> Seq.filter (fun (x, y) -> getCellByCoordinates x y bingo.SelectedCells |> Option.isSome)
  100.             |> Seq.length
  101.             |> (=) (secondDiagonal |> Seq.length)
  102.  
  103.         isDiagonal1 || isDiagonal2 ||
  104.         isHorizontalWin || isVerticalWin
  105.  
  106.     let placeValue selectedValue x y bingo =
  107.         let cell = bingo.Cells |> getCellByCoordinates x y
  108.  
  109.         match cell with
  110.         | Some { Value = value } when value = selectedValue ->
  111.             let selectedCell = { Value = value; X = x; Y = y }
  112.  
  113.             let newBingo = { bingo with SelectedCells = bingo.SelectedCells.Add selectedCell }
  114.  
  115.             let gameState = if detectWin newBingo then Winner [] else NotFound
  116.  
  117.             { newBingo with GameState = gameState }
  118.  
  119.         | _ -> bingo
  120.  
  121.     let view (bingo: Bingo) =
  122.         let cellOptionToString = Option.map(fun { Value = (Value i) } -> i.ToString()) >> Option.defaultValue ""
  123.  
  124.         let isSelected x y bingo =
  125.             bingo.SelectedCells
  126.             |> getCellByCoordinates x y
  127.             |> Option.isSome
  128.  
  129.         seq {
  130.             yield seq { yield "   "; yield! ([0..bingo.Height - 1] |> Seq.map(string) |> Seq.map(fun s -> s.PadLeft(4)))}
  131.             yield seq { yield "   "; yield! ([0..bingo.Height - 1] |> Seq.map(fun _ -> "____")) }
  132.             for y in [0..bingo.Height - 1] do                
  133.                 yield seq { yield y.ToString() + "|"; yield! seq {
  134.                             for x in [0..bingo.Width - 1] do
  135.                                 let optionCell = (bingo.Cells |> getCellByCoordinates x y)
  136.                                 let cellOptionString = optionCell |> cellOptionToString
  137.                                 let cellValue =
  138.                                     if isSelected x y bingo
  139.                                     then ((sprintf "[%s]") cellOptionString)
  140.                                     else cellOptionString
  141.  
  142.                                 yield cellValue
  143.                         }
  144.                 }
  145.         }
  146.         |> Seq.map (Seq.map (fun s -> s.PadLeft(4)) >> String.concat " ")
  147.         |> String.concat "\n"
  148.  
  149. module GameProcessor =
  150.     open BingoModule
  151.     open EndGameModule
  152.  
  153.     type CurrentGameState =
  154.         | Title of GameTitle
  155.         | Bingo of Bingo * Generator
  156.         | EndGame of EndGameTitle
  157.         | Exit
  158.  
  159.     type Events =
  160.         | TitleEvents of TitleEvents
  161.         | BingoEvents of BingoEvents
  162.         | EndGameEvents of EndGameEvents
  163.  
  164.     let private applyEvent currentGameState event =
  165.         match currentGameState, event with
  166.         | Title _, TitleEvents titleEvents ->
  167.             match titleEvents with
  168.             | TitleEvents.Start ->
  169.                 let generator = generateGenerator()
  170.                 Bingo (generateBingo 5 5 generator.Generate, generator)
  171.             | TitleEvents.Exit -> EndGame (EndGameTitle "Bye")
  172.         | Bingo ({ GameState = (Winner cells) }, _), _ ->
  173.             EndGame (EndGameTitle (sprintf "Well done! %A" cells))
  174.         | Bingo (bingoModel, generator), BingoEvents bingoEvents ->
  175.             match bingoEvents with
  176.             | BingoEvents.PlaceValue (x, y, value) -> Bingo (bingoModel |> placeValue value x y, generator)
  177.             | BingoEvents.Exit -> EndGame (EndGameTitle "Bye!")
  178.         | EndGame _, EndGameEvents endGameEvent ->
  179.             match endGameEvent with
  180.             | EndGameEvents.PlayAgain -> Title (GameTitle "Bingo!")
  181.             | EndGameEvents.Exit -> EndGame (EndGameTitle "Bye")
  182.         | _ -> failwith "Impossible"
  183.  
  184.     let processEvents events currentGameState =
  185.         events |> Seq.fold applyEvent currentGameState
  186.  
  187.     let init = Title (GameTitle "Bingo! (press 's' to start!)")
  188.  
  189.     let view = function
  190.         | CurrentGameState.Title title -> TitleModule.view title
  191.         | CurrentGameState.Bingo (bingo, _)  -> BingoModule.view bingo
  192.         | CurrentGameState.EndGame endGame -> EndGameModule.view endGame
  193.         | CurrentGameState.Exit _ -> ""
  194. open GameProcessor
  195. open System.Threading
  196.  
  197. [<EntryPoint>]
  198. let main _ =
  199.  
  200.     let rec untilPressed regex =
  201.         let consoleOutput = Console.ReadLine()
  202.  
  203.         match Regex.IsMatch(consoleOutput, regex) with
  204.         | true -> Regex.Matches(consoleOutput, regex)
  205.                         .Cast<Match>()
  206.                         .First()
  207.                         .Groups
  208.                         .Cast<Group>()
  209.                         .ToList()
  210.                         |> List.ofSeq
  211.                         |> List.map(fun x -> x.Value)
  212.         | false -> untilPressed regex
  213.  
  214.     let isPressed char =
  215.         let rec loop acc =
  216.             if Console.KeyAvailable then
  217.                 loop (Console.ReadKey().KeyChar::acc)
  218.             else acc
  219.        
  220.         loop [] |> List.exists((=) char)
  221.  
  222.     let run () =        
  223.         let rec loop state =
  224.             printfn "%s" (state |> GameProcessor.view)
  225.            
  226.             match state with
  227.             | CurrentGameState.EndGame _ ->
  228.                 Threading.Thread.Sleep(1000)
  229.                 state
  230.             | _ ->
  231.                 let events =
  232.                     seq {
  233.                         match state with
  234.                         | CurrentGameState.Title _ ->
  235.                             if isPressed 's' then yield TitleEvents (TitleEvents.Start)
  236.                             if isPressed 'x' then yield TitleEvents (TitleEvents.Exit)
  237.                         | CurrentGameState.Bingo (_, generator) ->
  238.                             let generatedValue = generator.Generate()
  239.  
  240.                             printfn "%A" generatedValue
  241.                             printfn "Input coordinaes:"
  242.  
  243.                             let x, y = untilPressed "(\d+) (\d+)" |> (fun m ->
  244.                                 printfn "%A" m
  245.                                 m.[1] |> int, m.[2] |> int)
  246.  
  247.                             yield BingoEvents (BingoModule.BingoEvents.PlaceValue (x, y, generatedValue) )
  248.                         | _ -> failwith "Unknown state"
  249.                     }
  250.                     |> Seq.toList
  251.  
  252.                 Thread.Sleep(1000)
  253.                
  254.                 Console.Clear()
  255.  
  256.                 loop (state |> GameProcessor.processEvents events)
  257.  
  258.         loop GameProcessor.init
  259.  
  260.     run () |> ignore
  261.  
  262.     0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement