Skip to content

Instantly share code, notes, and snippets.

@sungkmi
Last active February 23, 2024 10:28
Show Gist options
  • Save sungkmi/6aaa18b44bec454d77e3 to your computer and use it in GitHub Desktop.
Save sungkmi/6aaa18b44bec454d77e3 to your computer and use it in GitHub Desktop.
object Pegman extends App {
def minArrows(grid: IndexedSeq[IndexedSeq[Char]]): Option[Int] = {
val (row, column) = (grid.size, grid(0).size)
def isArrow: ((Int, Int)) => Boolean = { case (r, c) => "^v><" contains grid(r)(c) }
implicit class Grids(grids: Seq[(Int, Int)]) {
lazy val containsArrow: Boolean = grids map isArrow exists identity
}
def line(r: Int, c: Int)(direction: Char): Seq[(Int, Int)] = (direction match {
case '^' => 0 until r map { (_, c) }
case 'v' => r + 1 until row map { (_, c) }
case '<' => 0 until c map { (r, _) }
case '>' => c + 1 until column map { (r, _) }
}).toStream
def otherLines(r: Int, c: Int)(direction: Char) = "^v><" diff Seq(direction) flatMap line(r, c)
(for {
r <- 0 until row
c <- 0 until column
d = grid(r)(c) if isArrow(r, c)
} yield (r, c, d)).foldLeft[Option[Int]](Some(0)) {
case (Some(count), (r, c, d)) if line(r, c)(d).containsArrow => Some(count)
case (Some(count), (r, c, d)) if otherLines(r, c)(d).containsArrow => Some(count + 1)
case _ => None
}
}
def process(lineIn: Iterator[String])(lineOut: String => Unit) =
for (i <- 1 to lineIn.next().toInt) {
val Array(r, c) = lineIn.next() split ' ' map (_.toInt)
val grid = Vector.fill(r) { lineIn.next().toVector }
lineOut(s"Case #$i: ${minArrows(grid) getOrElse "IMPOSSIBLE"}")
}
val filename = "A-large-practice"
val writer = new java.io.PrintWriter(filename + ".out")
try {
process(io.Source.fromFile(filename + ".in").getLines) { s =>
writer.println(s); writer.flush()
}
} finally {
writer.flush(); writer.close()
}
}
import org.scalatest._
import Pegman._
class PegmanTest extends FunSuite {
test("sample #1") {
assert(minArrows(Vector("^".toVector, "^".toVector)) === Some(1))
}
test("sample #2") {
assert(minArrows(Vector(">v".toVector, "^<".toVector)) === Some(0))
}
test("sample #3") {
assert(minArrows(Vector("...".toVector, ".^.".toVector, "...".toVector)) === None)
}
test("sample #4") {
assert(minArrows(Vector(".".toVector)) === Some(0))
}
test("sample case") {
val input = """4
2 1
^
^
2 2
>v
^<
3 3
...
.^.
...
1 1
.""".lines
val expected = """Case #1: 1
Case #2: 0
Case #3: IMPOSSIBLE
Case #4: 0""".lines
lineComparison(input, expected)
}
test("full small case") {
val input = io.Source.fromFile("A-small-practice.in").getLines()
val expected = io.Source.fromFile("A-small-practice.out").getLines()
lineComparison(input, expected)
}
test("full large case") {
val input = io.Source.fromFile("A-large-practice.in").getLines()
val expected = io.Source.fromFile("A-large-practice.out").getLines()
lineComparison(input, expected)
}
def lineComparison(input: Iterator[String], expected: Iterator[String]) {
process(input) { s =>
for (line <- s.lines) assert(line.trim === expected.next().trim)
}
assert(expected.hasNext === false, "Finished too fast.")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment