object Bearing extends Enumeration {
val North = Value(0)
val East = Value(1)
val South = Value(2)
val West = Value(3)
}
case class Robot(bearing: Bearing.Value, pos: (Int, Int)) {
val DirectionCount = 4
def turnRight: Robot =
Robot(Bearing.apply((bearing.id + 1) % DirectionCount), pos)
def turnLeft: Robot =
Robot(
Bearing.apply((DirectionCount + (bearing.id - 1)) % DirectionCount),
pos
)
def coordinates: (Int, Int) = pos
def advance: Robot =
bearing match {
case Bearing.North => Robot(bearing, (pos._1, pos._2 + 1))
case Bearing.South => Robot(bearing, (pos._1, pos._2 - 1))
case Bearing.East => Robot(bearing, (pos._1 + 1, pos._2))
case Bearing.West => Robot(bearing, (pos._1 - 1, pos._2))
}
def simulate(orders: String): Robot =
orders.foldLeft(this)((robbie, cmd) =>
cmd match {
case 'L' => robbie.turnLeft
case 'R' => robbie.turnRight
case 'A' => robbie.advance
}
)
}
This approach starts by defining the Bearing
Enumeration in the Scala 2 way.
The Robot
class
starts by defining an immutable value that represents the count of the four directions being used
in the program.
The turnRight()
method uses the id
member of the Value
class
to get the value of the Enumeration
.
So, the id
of a variable set to Bearing.West
would be 3
.
The apply()
method is used to set a Bearing
Enumeration
from a value.
So, if the robot were facing west and turned right to the north, 1
would be added to its value of 3
, and the modulus operator
would give a remainder of 0
when divided by the DirectionCount
of 4
.
0
would be passed to apply()
, which would create a Bearing
of North
.
The turnLeft()
method uses the same methods.
So, if the robot were facing north and turned left to the west, 1
would be subracted from its value of 0
,
and -1
would be added to DirectionCount
to get 3
.
The modulus operator would give a remainder of 3
when divided by the DirectionCount
of 4
, and
3
would be passed to apply()
, which would create a Bearing
of West
.
if the robot were facing east and turned left to the north, 1
would be subracted from its value of 1
,
and 0
would be added to DirectionCount
to get 4
.
The modulus operator would give a remainder of 0
when divided by the DirectionCount
of 4
. and
0
would be passed to apply()
, which would create a Bearing
of North
.
At the time of the writing, Scala 3 is not yet supported on the Scala track.
The Scala 3 way of enum
s would be handled similarly, with the ordinal()
method functioning like
id
and the fromOrdinal()
method functioning like apply()
, like so:
enum Bearing {
case North, East, South, West
}
// code snipped
def turnRight: Robot =
Robot(Bearing.fromOrdinal((bearing.ordinal + 1) % DirectionCount), pos)
def turnLeft: Robot =
Robot(
Bearing.fromOrdinal(
(DirectionCount + (bearing.ordinal - 1)) % DirectionCount
),
pos
)
The simulate()
method uses the foldLeft()
method to iterate the characters of the orders String
.
def simulate(orders: String): Robot =
orders.foldLeft(this)((robbie, cmd) =>
cmd match {
case 'L' => robbie.turnLeft
case 'R' => robbie.turnRight
case 'A' => robbie.advance
}
)
The initial value for foldLeft()
is set to the Robot
instance.
The first iteration passes the Robot
instance and the first character of the orders String
into a lambda
which uses a match
for pattern matching on the command letter.
The match
returns a new Robot
which is passed to the next iteration of foldLeft
along with the next
character of the orders String
.
When foldLeft()
is done iterating through all of the letters, it returns the Robot
instance from its last iteration.