First commit
commit
2c99555ed7
@ -0,0 +1,87 @@
|
|||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
To run the test suite, execute the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
stack test
|
||||||
|
```
|
||||||
|
|
||||||
|
#### If you get an error message like this...
|
||||||
|
|
||||||
|
```
|
||||||
|
No .cabal file found in directory
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```
|
||||||
|
RedownloadInvalidResponse Request {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
"/home/username/.stack/build-plan/lts-xx.yy.yaml" (Response {responseStatus = Status {statusCode = 404, statusMessage = "Not Found"},
|
||||||
|
```
|
||||||
|
|
||||||
|
You are probably running an old stack version and need
|
||||||
|
to upgrade it. Try running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
stack upgrade
|
||||||
|
```
|
||||||
|
|
||||||
|
Or see other options for upgrading at [Stack documentation](https://docs.haskellstack.org/en/stable/install_and_upgrade/#upgrade).
|
||||||
|
|
||||||
|
#### Otherwise, if you get an error message like this...
|
||||||
|
|
||||||
|
```
|
||||||
|
No compiler found, expected minor version match with...
|
||||||
|
Try running "stack setup" to install the correct GHC...
|
||||||
|
```
|
||||||
|
|
||||||
|
Just do as it says and it will download and install
|
||||||
|
the correct compiler version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
stack setup
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to play with your solution in GHCi, just run the command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
stack ghci
|
||||||
|
```
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit src/GameOfLife.hs package.yaml` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [Haskell track's documentation](https://exercism.org/docs/tracks/haskell)
|
||||||
|
- The [Haskell track's programming category on the forum](https://forum.exercism.org/c/programming/haskell)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
Please refer to the [installation](https://exercism.io/tracks/haskell/installation)
|
||||||
|
and [learning](https://exercism.io/tracks/haskell/learning) help pages.
|
||||||
|
|
||||||
|
## Feedback, Issues, Pull Requests
|
||||||
|
|
||||||
|
The [exercism/haskell](https://github.com/exercism/haskell) repository on
|
||||||
|
GitHub is the home for all of the Haskell exercises.
|
||||||
|
|
||||||
|
If you have feedback about an exercise, or want to help implementing a new
|
||||||
|
one, head over there and create an issue. We'll do our best to help you!
|
@ -0,0 +1,36 @@
|
|||||||
|
# Game of Life
|
||||||
|
|
||||||
|
Welcome to Game of Life on Exercism's Haskell Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
[Conway's Game of Life][game-of-life] is a fascinating cellular automaton created by the British mathematician John Horton Conway in 1970.
|
||||||
|
|
||||||
|
The game consists of a two-dimensional grid of cells that can either be "alive" or "dead."
|
||||||
|
|
||||||
|
After each generation, the cells interact with their eight neighbors via a set of rules, which define the new generation.
|
||||||
|
|
||||||
|
[game-of-life]: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
After each generation, the cells interact with their eight neighbors, which are cells adjacent horizontally, vertically, or diagonally.
|
||||||
|
|
||||||
|
The following rules are applied to each cell:
|
||||||
|
|
||||||
|
- Any live cell with two or three live neighbors lives on.
|
||||||
|
- Any dead cell with exactly three live neighbors becomes a live cell.
|
||||||
|
- All other cells die or stay dead.
|
||||||
|
|
||||||
|
Given a matrix of 1s and 0s (corresponding to live and dead cells), apply the rules to each cell, and return the next generation.
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @tofische
|
||||||
|
|
||||||
|
### Based on
|
||||||
|
|
||||||
|
Wikipedia - https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
|
@ -0,0 +1,34 @@
|
|||||||
|
cabal-version: 1.12
|
||||||
|
|
||||||
|
-- This file has been generated from package.yaml by hpack version 0.37.0.
|
||||||
|
--
|
||||||
|
-- see: https://github.com/sol/hpack
|
||||||
|
|
||||||
|
name: game-of-life
|
||||||
|
version: 1.0.0.0
|
||||||
|
build-type: Simple
|
||||||
|
|
||||||
|
library
|
||||||
|
exposed-modules:
|
||||||
|
GameOfLife
|
||||||
|
other-modules:
|
||||||
|
Paths_game_of_life
|
||||||
|
hs-source-dirs:
|
||||||
|
src
|
||||||
|
ghc-options: -Wall
|
||||||
|
build-depends:
|
||||||
|
base
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
test-suite test
|
||||||
|
type: exitcode-stdio-1.0
|
||||||
|
main-is: Tests.hs
|
||||||
|
other-modules:
|
||||||
|
Paths_game_of_life
|
||||||
|
hs-source-dirs:
|
||||||
|
test
|
||||||
|
build-depends:
|
||||||
|
base
|
||||||
|
, game-of-life
|
||||||
|
, hspec
|
||||||
|
default-language: Haskell2010
|
@ -0,0 +1,21 @@
|
|||||||
|
name: game-of-life
|
||||||
|
version: 1.0.0.0
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- base
|
||||||
|
|
||||||
|
library:
|
||||||
|
exposed-modules: GameOfLife
|
||||||
|
source-dirs: src
|
||||||
|
ghc-options: -Wall
|
||||||
|
# dependencies:
|
||||||
|
# - foo # List here the packages you
|
||||||
|
# - bar # want to use in your solution.
|
||||||
|
|
||||||
|
tests:
|
||||||
|
test:
|
||||||
|
main: Tests.hs
|
||||||
|
source-dirs: test
|
||||||
|
dependencies:
|
||||||
|
- game-of-life
|
||||||
|
- hspec
|
@ -0,0 +1,59 @@
|
|||||||
|
module GameOfLife (tick) where
|
||||||
|
|
||||||
|
type Grid = [[Int]]
|
||||||
|
|
||||||
|
-- Maps a function over every element in a grid
|
||||||
|
gridMap :: (a -> b) -> [[a]] -> [[b]]
|
||||||
|
gridMap f = map (map f)
|
||||||
|
|
||||||
|
-- Param 1: The current value of the cell
|
||||||
|
-- Param 2: The number of living neighbors
|
||||||
|
-- Return value: The next value of the cell
|
||||||
|
nextIterHelper :: Int -> Int -> Int
|
||||||
|
nextIterHelper 1 2 = 1
|
||||||
|
nextIterHelper 1 3 = 1
|
||||||
|
nextIterHelper 0 3 = 1
|
||||||
|
nextIterHelper _ _ = 0
|
||||||
|
|
||||||
|
-- Returns the value of a specific cell in a grid - out-of-bounds is always zero
|
||||||
|
cellVal :: Grid -> (Int, Int) -> Int
|
||||||
|
cellVal grid (x,y)
|
||||||
|
| x < 0 || y < 0 = 0
|
||||||
|
| y >= length (grid) || x >= length (grid!!0) = 0
|
||||||
|
| otherwise = (grid!!y)!!x
|
||||||
|
|
||||||
|
-- Given a tuple (representing the location of a cell),
|
||||||
|
-- it returns a list of tuples that are the locations of the neighbors
|
||||||
|
neighbors :: (Int, Int) -> [(Int, Int)]
|
||||||
|
neighbors (x, y) = [(a,b) | a <- dx, b <- dy, a /= x || b /= y]
|
||||||
|
where dx = [x-1..x+1]
|
||||||
|
dy = [y-1..y+1]
|
||||||
|
|
||||||
|
-- Predicate - returns whether the cell is alive or not
|
||||||
|
isAlive :: Grid -> (Int,Int) -> Bool
|
||||||
|
isAlive grid tup = if (cellVal grid tup) == 1 then True else False
|
||||||
|
|
||||||
|
-- Filter function that takes a list of indexes in a grid, and only returns the ones
|
||||||
|
-- where the cell value is 1
|
||||||
|
keepAliveCells :: Grid -> [(Int,Int)] -> [(Int,Int)]
|
||||||
|
keepAliveCells grid tups = filter (isAlive grid) tups
|
||||||
|
|
||||||
|
-- Returns the number of alive neighbors of the given cell
|
||||||
|
numAliveNeighbors :: Grid -> (Int,Int) -> Int
|
||||||
|
numAliveNeighbors grid tup = (length . keepAliveCells grid . neighbors) tup
|
||||||
|
|
||||||
|
-- Given the grid and the location of a cell, returns the next value of the cell
|
||||||
|
nextIter :: Grid -> (Int, Int) -> Int
|
||||||
|
nextIter grid tup = nextIterHelper (cellVal grid tup) (numAliveNeighbors grid tup)
|
||||||
|
|
||||||
|
-- Returns a grid of all cell indices in the grid
|
||||||
|
cellIndices :: Grid -> [[(Int,Int)]]
|
||||||
|
cellIndices [[]] = [[]]
|
||||||
|
cellIndices grid = [[(x,y) | x <- [0..xdim-1]] | y <- [0..ydim-1]]
|
||||||
|
where xdim = length (grid!!0)
|
||||||
|
ydim = length grid
|
||||||
|
|
||||||
|
tick :: Grid -> Grid
|
||||||
|
tick [] = []
|
||||||
|
tick [[]] = [[]]
|
||||||
|
tick grid = gridMap (nextIter grid) (cellIndices grid)
|
@ -0,0 +1 @@
|
|||||||
|
resolver: lts-20.18
|
@ -0,0 +1,12 @@
|
|||||||
|
# This file was autogenerated by Stack.
|
||||||
|
# You should not edit this file by hand.
|
||||||
|
# For more information, please see the documentation at:
|
||||||
|
# https://docs.haskellstack.org/en/stable/lock_files
|
||||||
|
|
||||||
|
packages: []
|
||||||
|
snapshots:
|
||||||
|
- completed:
|
||||||
|
sha256: 9fa4bece7acfac1fc7930c5d6e24606004b09e80aa0e52e9f68b148201008db9
|
||||||
|
size: 649606
|
||||||
|
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/18.yaml
|
||||||
|
original: lts-20.18
|
@ -0,0 +1,125 @@
|
|||||||
|
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
|
||||||
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
|
||||||
|
import Data.Foldable (for_)
|
||||||
|
import Test.Hspec (Spec, describe, it, shouldBe)
|
||||||
|
import Test.Hspec.Runner (configFailFast, defaultConfig, hspecWith)
|
||||||
|
|
||||||
|
import GameOfLife (tick)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = hspecWith defaultConfig {configFailFast = True} specs
|
||||||
|
|
||||||
|
specs :: Spec
|
||||||
|
specs = describe "tick" $ for_ cases test
|
||||||
|
where
|
||||||
|
|
||||||
|
test Case{..} = it description assertion
|
||||||
|
where
|
||||||
|
assertion = tick matrix `shouldBe` expected
|
||||||
|
|
||||||
|
data Case = Case { description :: String
|
||||||
|
, matrix :: [[Int]]
|
||||||
|
, expected :: [[Int]]
|
||||||
|
}
|
||||||
|
|
||||||
|
cases :: [Case]
|
||||||
|
cases = [ Case { description = "Empty matrix"
|
||||||
|
, matrix = []
|
||||||
|
, expected = []
|
||||||
|
}
|
||||||
|
, Case { description = "Live cells with zero live neighbors die"
|
||||||
|
, matrix = [
|
||||||
|
[0, 0, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 0, 0]
|
||||||
|
]
|
||||||
|
, expected = [
|
||||||
|
[0, 0, 0],
|
||||||
|
[0, 0, 0],
|
||||||
|
[0, 0, 0]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
, Case { description = "Live cells with only one live neighbor die"
|
||||||
|
, matrix = [
|
||||||
|
[0, 0, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0]
|
||||||
|
]
|
||||||
|
, expected = [
|
||||||
|
[0, 0, 0],
|
||||||
|
[0, 0, 0],
|
||||||
|
[0, 0, 0]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
, Case { description = "Live cells with two live neighbors stay alive"
|
||||||
|
, matrix = [
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1]
|
||||||
|
]
|
||||||
|
, expected = [
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 0, 1],
|
||||||
|
[0, 0, 0]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
, Case { description = "Live cells with three live neighbors stay alive"
|
||||||
|
, matrix = [
|
||||||
|
[0, 1, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 1, 0]
|
||||||
|
]
|
||||||
|
, expected = [
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 1, 0]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
, Case { description = "Dead cells with three live neighbors become alive"
|
||||||
|
, matrix = [
|
||||||
|
[1, 1, 0],
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 0, 0]
|
||||||
|
]
|
||||||
|
, expected = [
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 1, 0],
|
||||||
|
[0, 0, 0]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
, Case { description = "Live cells with four or more neighbors die"
|
||||||
|
, matrix = [
|
||||||
|
[1, 1, 1],
|
||||||
|
[1, 1, 1],
|
||||||
|
[1, 1, 1]
|
||||||
|
]
|
||||||
|
, expected = [
|
||||||
|
[1, 0, 1],
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 0, 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
, Case { description = "Bigger matrix"
|
||||||
|
, matrix = [
|
||||||
|
[1, 1, 0, 1, 1, 0, 0, 0],
|
||||||
|
[1, 0, 1, 1, 0, 0, 0, 0],
|
||||||
|
[1, 1, 1, 0, 0, 1, 1, 1],
|
||||||
|
[0, 0, 0, 0, 0, 1, 1, 0],
|
||||||
|
[1, 0, 0, 0, 1, 1, 0, 0],
|
||||||
|
[1, 1, 0, 0, 0, 1, 1, 1],
|
||||||
|
[0, 0, 1, 0, 1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 0, 0, 0, 1, 1]
|
||||||
|
]
|
||||||
|
, expected = [
|
||||||
|
[1, 1, 0, 1, 1, 0, 0, 0],
|
||||||
|
[0, 0, 0, 0, 0, 1, 1, 0],
|
||||||
|
[1, 0, 1, 1, 1, 1, 0, 1],
|
||||||
|
[1, 0, 0, 0, 0, 0, 0, 1],
|
||||||
|
[1, 1, 0, 0, 1, 0, 0, 1],
|
||||||
|
[1, 1, 0, 1, 0, 0, 0, 1],
|
||||||
|
[1, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
[0, 0, 0, 0, 0, 0, 1, 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue