// position on the field
type Position = {
  // return row or column of the position
  row -> Number
  col -> Number
  
  // return a position one cell in dir direction from self
  translate (dir: Direction) -> Position
}

// create a position on the field at (r,c)
// notice that r affect the y coordinate and c the x coordinate
class positionRow (r: Number) col (c: Number) -> Position {
  // return row or column of the position
  method row -> Number {r}
  method col -> Number {c}
  
  // check to see if contents of two position are the same
  method == (other: Position) -> Boolean {
    (row == other.row) && (col == other.col)
  } 
  
  // return a position one cell in dir direction from self
  method translate (dir: Direction) -> Position {
    positionRow (r + dir.rowChange) col (c + dir.colChange)
  }
  
  // return string describing row and column of position
  method asString -> String {
    "Position at row {row}, column {col}"
  }
}

type Direction = {
  // how much to change row/column if move in this direction
  rowChange -> Number
  colChange -> Number
  
  // whether this direction is opposite to newDirection
  isOpposite (newDirection: Direction) -> Boolean
  
  // string representation of the direction
  asString -> String
}

class directionBy (rowChange': Number, colChange': Number) -> Direction is confidential {
  // how much to change row/column if move in this direction
  method rowChange -> Number {rowChange'}
  method colChange -> Number {colChange'}
  
  // whether this direction is opposite to newDirection
  method isOpposite(newDirection: Direction) -> Boolean {
    (rowChange == -newDirection.rowChange) &&
    (colChange == -newDirection.colChange)
  }

  // string representation of the direction
  method asString -> String {
    "({rowChange}, {colChange})"
  }
}

// constants indicating the cardinal directions
def up: Direction is public = directionBy (-1,0)
def down: Direction is public = directionBy (1,0)
def left: Direction is public = directionBy (0, -1)
def right: Direction is public = directionBy (0, 1)