This is day 25 of my 30 day Elm challenge
Today we'll create a very basic chess board view from a 8x8 List
.
This is the final result:
A8B8C8D8E8F8G8H8
A7B7C7D7E7F7G7H7
A6B6C6D6E6F6G6H6
A5B5C5D5E5F5G5H5
A4B4C4D4E4F4G4H4
A3B3C3D3E3F3G3H3
A2B2C2D2E2F2G2H2
A1B1C1D1E1F1G1H1
Demo/code: https://ellie-app.com/c3QTnvkpn7ha1
- 1. Creating a single row
- 2. Creating a grid (list of rows)
- 3. Creating a grid with chess position names (A1, A2, .. H8)
- 4. Refactoring: Named functions look nicer than long anonymous ones
- 5. Creating the view
1. Creating a single row
This is easy in Elm:
List.range 1 8 -- [1, 2, 3, 4, 5, 6, 7, 8]
If you want the list to contain something else, you can use List.map
:
List.range 1 8
|> List.map (\item -> "lol") -- ["lol", "lol", "lol", "lol", "lol", "lol", "lol", "lol", ]
2. Creating a grid (list of rows)
Instead of having a list of numbers, we can imagine each number being replaced with a List
:
verySimpleGrid : List (List Int)
verySimpleGrid =
List.range 1 8 -- [1, 2, 3, 4, 5, 6, 7, 8]
|> List.map (\number -> List.range 1 8)
-- Each individual number in the previous list is replaced with [1, 2, 3, 4, 5, 6, 7, 8]
-- [[1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7, 8], etc]
3. Creating a grid with chess position names (A1, A2, .. H8)
This was my initial approach:
letters : String
letters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
grid : List (List String)
grid =
List.range 1 8
|> List.map (\row -> List.range 1 8)
|> List.indexedMap
(\y row ->
List.map
(\x ->
String.slice (x - 1) (x + 0) letters ++ String.fromInt (y + 1)
)
row
)
|> List.reverse
letters
is one of my favorite hardcoded things I've done. Very nice!
The first two lines of the grid function are the same as before.
List.indexedMap
works the same way as JavaScript's regular Array.map
, except it's index first, and then element.
- First, we're getting the Y index and its row (
List String
). - Then, using
List.map
onrow
, we get each X value. - The X coordinates should go from A to H. This is done with String.slice, which cuts from index1 up to (not including) index2.
- The Y coordinates work as usual, except chess board have 1-based indexing.
- The rows are reversed, so that A1 isn't at the top of the board.
4. Refactoring: Named functions look nicer than long anonymous ones
Looking at the code above, all that indentation is awkward to read, and none of the functions passed to List.map
or List.indexedMap
are reusable.
I get shivers from anonymous functions that span more than one line. I'm feeling lazy today, but I'm doing this just so I can sleep well at night.
letters : String
letters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
singleCell : Int -> Int -> String
singleCell x y =
String.slice (x - 1) (x + 0) letters ++ String.fromInt (y + 1)
chessRow : Int -> List Int -> List String
chessRow y row =
row |> List.map (\x -> singleCell x y)
grid : List (List String)
grid =
List.range 1 8
|> List.map (\row -> List.range 1 8)
|> List.indexedMap chessRow
|> List.reverse
I think that is so much nicer to read, I'm actually a bit impressed at how much of a difference that makes.
5. Creating the view
All that's left is getting the grid displayed in the browser. I guess I could have done nested List.map
s, but again, I think separate functions look nicer.
First, we need to put each row into one div.
Then those divs all get put into one main div.
rowDiv : List String -> Html a
rowDiv row =
div [] (row |> List.map (\boardPosition -> text boardPosition))
main : Html a
main =
div [] (grid |> List.map rowDiv)
Looking good. See you tomorrow!
Top comments (0)