Skip to content

Commit

Permalink
fix initialize fn
Browse files Browse the repository at this point in the history
  • Loading branch information
BrianHicks committed Feb 21, 2020
1 parent 63f6fde commit 597b828
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/Grid.elm
Expand Up @@ -28,8 +28,8 @@ initialize { rows, columns } init =
Array.initialize (rows * columns)
(\i ->
init
{ row = i // rows
, column = modBy rows i
{ row = i // columns
, column = modBy columns i
}
)
, width = columns
Expand Down
24 changes: 24 additions & 0 deletions tests/GridTests.elm
Expand Up @@ -3,6 +3,7 @@ module GridTests exposing (..)
import Expect
import Fuzz exposing (Fuzzer)
import Grid exposing (Grid)
import SlowGrid
import Test exposing (..)


Expand Down Expand Up @@ -60,6 +61,29 @@ windowsTest =
]



{- Tests for compatibility with the older, slower, but known-good version. -}


compatibilityTest : Test
compatibilityTest =
describe "compatibility with the array-of-arrays implementation"
[ fuzz2 (Fuzz.intRange 0 2) (Fuzz.intRange 0 2) "initialize" <|
\rows columns ->
let
initter =
\{ row, column } -> ( row, column )

expected =
SlowGrid.toArrays (SlowGrid.initialize { rows = rows, columns = columns } identity)

actual =
Grid.toArrays (Grid.initialize { rows = rows, columns = columns } identity)
in
Expect.equal expected actual
]


blank10x10 : Grid Int
blank10x10 =
Grid.initialize { rows = 10, columns = 10 } (always 0)
Expand Down
221 changes: 221 additions & 0 deletions tests/SlowGrid.elm
@@ -0,0 +1,221 @@
module SlowGrid exposing (FromRowsAndColumnsProblem, Grid, fromRowsAndColumns, fromRowsAndColumnsArray, get, getWrapping, indexedMap, initialize, map, rotate, set, toArrays, topLeft, update, view, windows)

import Array exposing (Array)
import Color.Transparent as Color exposing (Color)
import Css
import Html.Styled as Html exposing (Html)
import Html.Styled.Attributes as Attrs exposing (css, style)
import Set


type Grid a
= Grid
{ -- rows x columns
items : Array (Array a)
, width : Int
, height : Int
}


type FromRowsAndColumnsProblem
= MoreThanOneWidth (List Int)


initialize : { rows : Int, columns : Int } -> ({ row : Int, column : Int } -> a) -> Grid a
initialize { rows, columns } init =
Grid
{ items = Array.initialize rows (\row -> Array.initialize columns (\colNum -> init { row = row, column = colNum }))
, width = columns
, height = rows
}


{-| Construct a grid from a list of lists. The outer list is a list of rows,
and the inner lists are values in columns.
If the sizes of the column arrays (the inner ones) don't match up, you'll get a
`MoreThanOneWidth` error back from this function.
-}
fromRowsAndColumns : List (List a) -> Grid a
fromRowsAndColumns rowsAndColumns =
Array.fromList (List.map Array.fromList rowsAndColumns)
|> fromRowsAndColumnsArray


fromRowsAndColumnsArray : Array (Array a) -> Grid a
fromRowsAndColumnsArray rowsAndColumns =
Grid
{ items = rowsAndColumns
, width =
Array.get 0 rowsAndColumns
|> Maybe.map Array.length
|> Maybe.withDefault 0
, height = Array.length rowsAndColumns
}


toArrays : Grid a -> Array (Array a)
toArrays (Grid { items }) =
items


{-| Rotate a grid 90° clockwise.
-}
rotate : Grid a -> Grid a
rotate ((Grid { width, height }) as grid) =
let
newItems =
List.range 0 (width - 1)
|> List.map
(\col ->
column col grid
|> Maybe.withDefault Array.empty
|> Array.foldr Array.push Array.empty
)
|> Array.fromList
in
Grid
{ items = newItems
, height = width
, width = height
}


column : Int -> Grid a -> Maybe (Array a)
column colNum (Grid { items, height }) =
List.range 0 (height - 1)
|> List.foldl
(\row soFar ->
Maybe.andThen
(\arr ->
items
|> Array.get row
|> Maybe.andThen (Array.get colNum)
|> Maybe.map (\val -> Array.push val arr)
)
soFar
)
(Just Array.empty)


{-| Get a number of windows over the given grid data. Windows wrap around the
edges of the input grid. We include tuples here, as they're useful as IDs.
-}
windows : { width : Int, height : Int } -> Grid a -> Grid (Grid a)
windows sizes (Grid { width, height, items }) =
let
-- when we reach the edge, we just need to wrap around.
-- Repeating once per axis should do it!
expanded =
Array.initialize (height * 2)
(\i ->
let
row =
items
|> Array.get (modBy height i)
|> Maybe.withDefault Array.empty
in
Array.append row row
)
in
Grid
{ items =
Array.initialize height
(\row ->
Array.initialize width
(\col ->
Grid
{ items =
expanded
|> Array.slice row (row + sizes.height)
|> Array.map (Array.slice col (col + sizes.width))
, width = sizes.width
, height = sizes.height
}
)
)
, width = width
, height = height
}


get : { row : Int, column : Int } -> Grid a -> Maybe a
get coords (Grid { items }) =
items
|> Array.get coords.row
|> Maybe.andThen (Array.get coords.column)


{-| Still a maybe because the grid could be empty
-}
getWrapping : { row : Int, column : Int } -> Grid a -> Maybe a
getWrapping coords ((Grid { width, height }) as grid) =
get
{ row = modBy height coords.row
, column = modBy width coords.column
}
grid


topLeft : Grid a -> Maybe a
topLeft =
get { row = 0, column = 0 }


set : { row : Int, column : Int } -> a -> Grid a -> Grid a
set coords newValue (Grid grid) =
case Array.get coords.row grid.items of
Nothing ->
Grid grid

Just row ->
Grid
{ grid
| items =
Array.set
coords.row
(Array.set coords.column newValue row)
grid.items
}


update : (a -> a) -> { row : Int, column : Int } -> Grid a -> Grid a
update fn coords grid =
case get coords grid of
Just item ->
set coords (fn item) grid

Nothing ->
grid


{-| TODO: could probably do this with CSS grids but I'm not sure how.
-}
view : (a -> Html msg) -> Grid a -> Html msg
view viewItem (Grid { items }) =
items
|> Array.map (Array.map viewItem >> Array.toList >> Html.tr [])
|> Array.toList
|> Html.table [ css [ Css.borderCollapse Css.collapse ] ]


indexedMap : ({ row : Int, column : Int } -> a -> b) -> Grid a -> Grid b
indexedMap fn (Grid grid) =
Grid
{ items =
Array.indexedMap
(\rowNum row ->
Array.indexedMap
(\colNum val -> fn { row = rowNum, column = colNum } val)
row
)
grid.items
, width = grid.width
, height = grid.height
}


map : (a -> b) -> Grid a -> Grid b
map fn =
indexedMap (\_ a -> fn a)

0 comments on commit 597b828

Please sign in to comment.