From cb42276f49558047233927b8f60564e521dced04 Mon Sep 17 00:00:00 2001 From: nih0n Date: Sun, 11 Aug 2024 17:00:00 -0300 Subject: [PATCH 1/3] Read Life file --- README.md | 6 ++---- app/Main.hs | 14 ++++++++++++-- examples/Blinker.life | 4 ++++ examples/Glider.life | 6 ++++++ h-vita.cabal | 13 ++++++++++++- package.yaml | 3 +++ src/Display.hs | 15 ++++++++++++++- src/Options.hs | 32 ++++++++++++++++++++++++++++++++ src/Parser.hs | 23 +++++++++++++++++++++++ 9 files changed, 108 insertions(+), 8 deletions(-) create mode 100644 examples/Blinker.life create mode 100644 examples/Glider.life create mode 100644 src/Options.hs create mode 100644 src/Parser.hs diff --git a/README.md b/README.md index 305f438..f33b1ec 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,9 @@ This is the [game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life To execute the game you do: -`stack run` +`stack run -- -f -r -c ` -If you want to see a different game (not the glider one), open the REPL and use: - -`playGame OTHER_GAME` +It will load a `.life` file in a matrix of the specified size. You can read about the `Life` format [here](https://conwaylife.com/wiki/Life_1.06). ## Developers diff --git a/app/Main.hs b/app/Main.hs index a19896b..b7f1c0f 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -1,9 +1,19 @@ module Main where import GameOfLife -import Games import Display import Types +import Parser +import Text.Megaparsec +import Options.Applicative +import qualified Data.Text as T +import Options (parseOptions, Options(..)) main :: IO () -main = playGame gliderGrid +main = do + options <- execParser parseOptions + contents <- readFile (file options) + let positions = runParser parseLife (file options) (T.pack contents) + case positions of + Left err -> print err + Right positions -> playGame $ createGrid (rows options) (cols options) positions diff --git a/examples/Blinker.life b/examples/Blinker.life new file mode 100644 index 0000000..a5ff4a9 --- /dev/null +++ b/examples/Blinker.life @@ -0,0 +1,4 @@ +#Life 1.06 +0 0 +1 0 +2 0 \ No newline at end of file diff --git a/examples/Glider.life b/examples/Glider.life new file mode 100644 index 0000000..4dd0a99 --- /dev/null +++ b/examples/Glider.life @@ -0,0 +1,6 @@ +#Life 1.06 +0 1 +1 2 +2 0 +2 1 +2 2 \ No newline at end of file diff --git a/h-vita.cabal b/h-vita.cabal index ad8173b..f0c3e14 100644 --- a/h-vita.cabal +++ b/h-vita.cabal @@ -1,6 +1,6 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4. +-- This file has been generated from package.yaml by hpack version 0.36.0. -- -- see: https://github.com/sol/hpack @@ -28,6 +28,8 @@ library Display GameOfLife Games + Options + Parser Types other-modules: Paths_h_vita @@ -37,6 +39,9 @@ library base >=4.7 && <5 , gloss , matrix + , megaparsec + , optparse-applicative + , text default-language: Haskell2010 executable h-vita-exe @@ -51,6 +56,9 @@ executable h-vita-exe , gloss , h-vita , matrix + , megaparsec + , optparse-applicative + , text default-language: Haskell2010 test-suite h-vita-test @@ -66,4 +74,7 @@ test-suite h-vita-test , gloss , h-vita , matrix + , megaparsec + , optparse-applicative + , text default-language: Haskell2010 diff --git a/package.yaml b/package.yaml index 46bc9fc..b8201bf 100644 --- a/package.yaml +++ b/package.yaml @@ -23,6 +23,9 @@ dependencies: - base >= 4.7 && < 5 - matrix - gloss +- optparse-applicative +- megaparsec +- text library: source-dirs: src diff --git a/src/Display.hs b/src/Display.hs index e4dd8ec..0469625 100644 --- a/src/Display.hs +++ b/src/Display.hs @@ -4,9 +4,22 @@ import Data.Matrix import Graphics.Gloss import Graphics.Gloss.Interface.Pure.Simulate import GameOfLife -import Games import Types +createGrid :: Int -> Int -> [Location] -> Matrix Cell +createGrid rows cols positions = matrix rows cols getCellState + where + centerRow = (rows + 1) `div` 2 + centerCol = (cols + 1) `div` 2 + + index :: Int -> Int -> Location + index x y = (centerRow - x, y - centerCol) + + getCellState :: Location -> Cell + getCellState (x, y) + | index x y `elem` positions = alive + | otherwise = dead + render :: DisplayCellSize -> Grid -> Picture render (width, height) grid = Pictures $ toList $ mapPos cellToRect grid where diff --git a/src/Options.hs b/src/Options.hs new file mode 100644 index 0000000..99a548f --- /dev/null +++ b/src/Options.hs @@ -0,0 +1,32 @@ +module Options where + +import Options.Applicative + +data Options = Options { + file :: FilePath, + rows :: Int, + cols :: Int +} + +parseOptions :: ParserInfo Options +parseOptions = info + (helper <*> ( + Options + <$> strOption ( + long "file" + <> short 'f' + <> metavar "FILE" + <> help "File path" + ) + <*> option auto ( + long "rows" + <> short 'r' + <> help "Number of rows" + ) + <*> option auto ( + long "columns" + <> short 'c' + <> help "Number of columns" + ) + )) + (fullDesc <> header "h-vita") diff --git a/src/Parser.hs b/src/Parser.hs new file mode 100644 index 0000000..11fdc9d --- /dev/null +++ b/src/Parser.hs @@ -0,0 +1,23 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Parser where + +import Types +import Text.Megaparsec ( Parsec, many, optional ) +import Text.Megaparsec.Char +import Data.Void +import Data.Text +import Text.Megaparsec.Char.Lexer (decimal, signed) + +type Parser = Parsec Void Text + +type Position = (Int, Int) + +parseLife :: Parser [Location] +parseLife = header *> many position + +header :: Parser Text +header = string "#Life 1.06" *> eol + +position :: Parser Location +position = (,) <$> (signed space decimal <* space) <*> (signed space decimal <* optional eol) \ No newline at end of file From adcabb5e1561bd7074ecf54cf9ca220d128516e9 Mon Sep 17 00:00:00 2001 From: nih0n Date: Mon, 12 Aug 2024 19:23:36 -0300 Subject: [PATCH 2/3] Remove unused type --- src/Parser.hs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Parser.hs b/src/Parser.hs index 11fdc9d..3e99d62 100644 --- a/src/Parser.hs +++ b/src/Parser.hs @@ -11,8 +11,6 @@ import Text.Megaparsec.Char.Lexer (decimal, signed) type Parser = Parsec Void Text -type Position = (Int, Int) - parseLife :: Parser [Location] parseLife = header *> many position From 5cd4089c8fc13d0819f2a0e505806203db1857eb Mon Sep 17 00:00:00 2001 From: nih0n Date: Mon, 12 Aug 2024 19:25:23 -0300 Subject: [PATCH 3/3] Remove Games.hs --- h-vita.cabal | 1 - src/Games.hs | 34 ---------------------------------- 2 files changed, 35 deletions(-) delete mode 100644 src/Games.hs diff --git a/h-vita.cabal b/h-vita.cabal index f0c3e14..66b9106 100644 --- a/h-vita.cabal +++ b/h-vita.cabal @@ -27,7 +27,6 @@ library exposed-modules: Display GameOfLife - Games Options Parser Types diff --git a/src/Games.hs b/src/Games.hs deleted file mode 100644 index ff778f5..0000000 --- a/src/Games.hs +++ /dev/null @@ -1,34 +0,0 @@ -module Games where - -import Types -import Data.Matrix - -beaconOscillatorGrid :: Grid -beaconOscillatorGrid = fromLists [ [dead, dead, dead, dead, dead, dead] - ,[dead, alive, alive, dead, dead, dead] - ,[dead, alive, alive, dead, dead, dead] - ,[dead, dead, dead, alive, alive, dead] - ,[dead, dead, dead, alive, alive, dead] - ,[dead, dead, dead, dead, dead, dead]] - -blinkerOscillatorGrid :: Grid -blinkerOscillatorGrid = fromLists [ [dead, dead, dead, dead, dead] - ,[dead, dead, alive, dead, dead] - ,[dead, dead, alive, dead, dead] - ,[dead, dead, alive, dead, dead] - ,[dead, dead, dead, dead, dead]] - -gliderGrid :: Grid -gliderGrid = fromLists [ [dead, alive, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, alive, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[alive, alive, alive, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead] - ,[dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead, dead]]