This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.

Matrix

A library for creating and using 2-D matrices/grids. Geared towards 2-D games.

Locations

type alias Location = ( Int, Int )

A representation of a row number and a column number, used to locate and access elements in a matrix.

loc : Int -> Int -> Location

Turn two integers into a location

row : Location -> Int

Extract the row number from a location

row (loc 3 5) == 3
col : Location -> Int

Extract the col number from a location

col (loc 3 5) == 5

Matrices

type alias Matrix a = Array.Array (Array.Array a)

An ordered collection of elements, all of a particular type, arranged into m rows and n columns.

Create

matrix : Int -> Int -> (Location -> a) -> Matrix a

Initialize a new matrix of size m x n. Delegates to a function of type Location -> a to determine value to place at each element in the matrix.

matrix 3 5 (\location ->
  if (isEven (row location)) then "Hello" else "World")

will give back the matrix

Hello Hello Hello Hello Hello
World World World World World
Hello Hello Hello Hello Hello
square : Int -> (Location -> a) -> Matrix a

Create a square matrix of a certain size

square 2 (\_ -> 'H') == H H
                        H H
fromList : List (List a) -> Matrix a

Convert a list of lists into a matrix

fromList [[1, 0], [0, 1]] == square 2 (\l -> if row l == col l then 1 else 0)

Transform

map : (a -> b) -> Matrix a -> Matrix b

Apply the function to every element in the matrix

map not (fromList [[True, False], [False, True]]) == fromList [[False, True], [True, False]]
mapWithLocation : (Location -> a -> b) -> Matrix a -> Matrix b

Apply the function to every element in the list, where the first function argument is the location of the element.

let
  m = (square 2 (\_ -> 1))
  f location element = if row location == col location
                        then element * 2
                        else element
in
  mapWithLocation f m == fromList [[2, 1], [1, 2]]
flatten : Matrix a -> List a

Convert a matrix to a single list

let
  m = fromList [[0, 1], [2, 3], [4, 5]]
in
  flatten m == [0, 1, 2, 3, 4, 5]

Get and Set

get : Location -> Matrix a -> Maybe a

Get the element at a particular location

get (loc -1 1) (square 2 (\_ -> True)) == Nothing

get (loc 1 1) (fromList [[0, 1], [2, 3]]) == Just 3
set : Location -> a -> Matrix a -> Matrix a

Set the element at a particular location

set (loc -1 1) 42 (square 2 (\_ -> True)) == square 2 (\_ -> True)

set (loc 1 1) 42 (fromList [[0, 1], [2, 3]]) == fromList [[0, 1], [2, 42]]
update : Location -> (a -> a) -> Matrix a -> Matrix a

Update the element at a particular location using the current value

Properties

colCount : Matrix a -> Int

Get the number of columns in a matrix

rowCount : Matrix a -> Int

Get the number of rows in a matrix

Convert to other types

toList : Matrix a -> List (List a)

Convert a matrix to a list of lists

toList (fromList [[1, 0], [0, 1]]) == [[1, 0], [0, 1]]
module Matrix exposing (..)

{-| A library for creating and using 2-D matrices/grids. Geared towards
2-D games.

# Locations

@docs Location, loc, row, col

# Matrices

@docs Matrix

## Create
@docs matrix, square, fromList

## Transform
@docs map, mapWithLocation, flatten

## Get and Set
@docs get, set, update

## Properties
@docs colCount, rowCount

## Convert to other types
@docs toList

-}

import Array
import List
import Maybe exposing (..)


{-| An ordered collection of elements, all of a particular type, arranged into `m` rows and `n` columns.

-}
type alias Matrix a =
    Array.Array (Array.Array a)


{-| A representation of a row number and a column number, used to locate and access elements in a matrix.
-}
type alias Location =
    ( Int, Int )


{-| Turn two integers into a location
-}
loc : Int -> Int -> Location
loc =
    (,)


{-| Extract the row number from a location

    row (loc 3 5) == 3

-}
row : Location -> Int
row =
    Tuple.first


{-| Extract the col number from a location

    col (loc 3 5) == 5

-}
col : Location -> Int
col =
    Tuple.second


{-| Create a square matrix of a certain size

    square 2 (\_ -> 'H') == H H
                            H H
-}
square : Int -> (Location -> a) -> Matrix a
square size =
    matrix size size


{-| Initialize a new matrix of size `m x n`.
Delegates to a function of type `Location -> a` to determine value to
place at each element in the matrix.

    matrix 3 5 (\location ->
      if (isEven (row location)) then "Hello" else "World")

will give back the matrix

    Hello Hello Hello Hello Hello
    World World World World World
    Hello Hello Hello Hello Hello
-}
matrix : Int -> Int -> (Location -> a) -> Matrix a
matrix numRows numCols f =
    Array.initialize numRows
        (\row ->
            Array.initialize numCols
                (\col -> f (loc row col))
        )


{-| Apply the function to every element in the matrix

    map not (fromList [[True, False], [False, True]]) == fromList [[False, True], [True, False]]
-}
map : (a -> b) -> Matrix a -> Matrix b
map f m =
    Array.map (Array.map f) m


{-| Apply the function to every element in the list, where the first function argument
is the location of the element.

    let
      m = (square 2 (\_ -> 1))
      f location element = if row location == col location
                            then element * 2
                            else element
    in
      mapWithLocation f m == fromList [[2, 1], [1, 2]]

-}
mapWithLocation : (Location -> a -> b) -> Matrix a -> Matrix b
mapWithLocation f m =
    Array.indexedMap
        (\rowNum row ->
            Array.indexedMap
                (\colNum element ->
                    f (loc rowNum colNum) element
                )
                row
        )
        m


{-| Convert a matrix to a list of lists

    toList (fromList [[1, 0], [0, 1]]) == [[1, 0], [0, 1]]

-}
toList : Matrix a -> List (List a)
toList m =
    Array.map Array.toList m
        |> Array.toList


{-| Convert a list of lists into a matrix

    fromList [[1, 0], [0, 1]] == square 2 (\l -> if row l == col l then 1 else 0)
-}
fromList : List (List a) -> Matrix a
fromList l =
    List.map Array.fromList l
        |> Array.fromList


{-| Convert a matrix to a single list

    let
      m = fromList [[0, 1], [2, 3], [4, 5]]
    in
      flatten m == [0, 1, 2, 3, 4, 5]
-}
flatten : Matrix a -> List a
flatten m =
    List.concat <| toList m


{-| Get the element at a particular location

    get (loc -1 1) (square 2 (\_ -> True)) == Nothing

    get (loc 1 1) (fromList [[0, 1], [2, 3]]) == Just 3
-}
get : Location -> Matrix a -> Maybe a
get location m =
    Array.get (row location) m |> andThen (Array.get (col location))


{-| Set the element at a particular location

    set (loc -1 1) 42 (square 2 (\_ -> True)) == square 2 (\_ -> True)

    set (loc 1 1) 42 (fromList [[0, 1], [2, 3]]) == fromList [[0, 1], [2, 42]]
-}
set : Location -> a -> Matrix a -> Matrix a
set location value m =
    update location (always value) m


{-| Update the element at a particular location using the current value

-}
update : Location -> (a -> a) -> Matrix a -> Matrix a
update location f m =
    get location m
        |> Maybe.map
            (\current ->
                Array.get (row location) m
                    |> Maybe.map
                        (\oldRow ->
                            Array.set (col location) (f current) oldRow
                                |> (\newRow -> Array.set (row location) newRow m)
                        )
                    |> Maybe.withDefault m
            )
        |> Maybe.withDefault m


{-| Get the number of columns in a matrix
-}
colCount : Matrix a -> Int
colCount m =
    Array.get 0 m
        |> Maybe.map Array.length
        |> Maybe.withDefault 0


{-| Get the number of rows in a matrix
-}
rowCount : Matrix a -> Int
rowCount m =
    Array.length m