Tic Tac ToeTopDefining Matrix

Defining Matrix

Nothing stops us from defining lists of lists. To declare a list, each of whose elements is a list of int:

  def twoDList: List<List<Number>> = list.empty

(A syntactic glitch in the compiler prevents us from writing the preferred:

  def twoDList: List<List<Number>> = list.empty<List<Number>>

That should be fixed in the near future.) Each element of twoDlist is a list of Numbers.

Despite the fact that Java will treat this as a list of lists, we usually think about this as a two-dimensional list, with the elements arranged in a two-dimensional table so that twoDlist.at(i).at(j) can be seen as the element in the ith row and jth column. For example here is the layout for a two-dimensional list a with 5 rows (numbered 1 to 5) and 3 columns:

1 2 3
1 a.at(1).at(1) a.at(1).at(2) a.at(1).at(3)
2 a.at(2).at(1) a.at(2).at(2) a.at(2).at(3)
3 a.at(3).at(1) a.at(3).at(2) a.at(3).at(3)
4 a.at(4).at(1) a.at(4).at(2) a.at(4).at(3)
5 a.at(5).at(1) a.at(5).at(2) a.at(5).at(3)

Viewed in this way, our two-dimensional list is a grid, much like a map or a spreadsheet. This is a natural way to store things like tables of data or matrices.

To make it easier to create and access elements of such a two-dimensional table we have created a class matrix generating objects of type Matrix. Matrix

We create a two-dimensional table by providing the type of values, the number of rows and columns, and the default value with which to initialize all slots. Thus we can create the two-dimensional list above by writing:

   def a:Matrix<Number> = matrix.size<Number>(5,3) defaultValue (0)

Type Matrix<T> is defined as follows:

type Matrix<T> = {
  at(r: Number, c: Number) -> T 
  at(r: Number, c: Number) put (value:T) -> Done
}

Thus we can access and update values by providing the row and column and, when updating, the new value.

A nested for loop is the most common way to access or update the elements of a two-dimensional list. One loop walks through the rows and the other walks through the columns. For example, if we wanted to assign a unique number to each cell of our two-dimensional list, we could do the following:

    for (1..5) do {row: Number ->
        for (1..3) do { col: Number -> 
            a.at(row,col)put(4*(row-1) + col)
        }
    }

This assigns the numbers 1 through 15 to the elements of list a. The list is filled by assigning values to the elements in the first row, then the second row, etc. and results in:

 1  2  3  
 4  5  6
 7  8  9
 10 11 12
 13 14 15

You could modify the above to be slightly more interesting by computing a multiplication table.

We could just as well process all the elements of column 1 first, then all of column 2, etc., by swapping the order of our loops:


    for (1..3) do {col: Number ->
        for (1..5) do {row: Number ->
            ...
         }
      }

For the most part, it doesn't matter which order you choose, though for large lists it is generally a good idea to traverse the list in the same order that your programming language will store the values in memory. In most languages the data is stored by rows, known as row major order. You will certainly see this again if you go on and take courses like Computer Organization or Operating Systems.


Tic Tac ToeTopDefining Matrix