lluque

AoC day 21

Dec 21st, 2016
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 4.05 KB | None | 0 0
  1. import scala.io.Source
  2.  
  3. object day21 extends App {
  4.  
  5.   val pattRd = """rotate (right|left) (\d) step[s]*""".r
  6.   val pattSp = """swap position (\d) with position (\d)""".r
  7.   val pattRp = """rotate based on position of letter (\w)""".r
  8.   val pattSl = """swap letter (\w) with letter (\w)""".r
  9.   val pattRv = """reverse positions (\d) through (\d)""".r
  10.   val pattMv = """move position (\d) to position (\d)""".r
  11.  
  12.   abstract class Command {
  13.     def exec(xs: String): String
  14.     def revert(xs: String): String
  15.   }
  16.  
  17.   trait RotateCommand {
  18.     def rotate(n: Int, xs: List[Char]): List[Char] = n match {
  19.       case i if i > 0 => xs match {
  20.         case h :: t => rotate(i - 1, t ::: List(h))
  21.         case Nil => rotate(i - 1, Nil)
  22.       }
  23.       case i if i < 0 => xs.reverse match {
  24.         case h :: t => rotate(i + 1, h :: t.reverse)
  25.         case Nil => rotate(i + 1, Nil)
  26.       }
  27.       case _ => xs
  28.     }
  29.   }
  30.  
  31.   case class Reverse(a: Int, b: Int) extends Command {
  32.     override def exec(xs: String): String = (xs take a) + xs.slice(a, b + 1).reverse + (xs takeRight xs.length - b - 1)
  33.     override def revert(xs: String): String = exec(xs)
  34.   }
  35.  
  36.   case class PositionSwap(a: Int, b: Int) extends Command {
  37.     override def exec(xs: String): String = xs.updated(a, xs(b)).updated(b, xs(a))
  38.     override def revert(xs: String): String = exec(xs)
  39.   }
  40.  
  41.   case class LetterSwap(a: Char, b: Char) extends Command {
  42.     override def exec(xs: String): String = {
  43.       def inner(xs: List[Char], acc: String): String = xs match {
  44.         case Nil => acc
  45.         case h :: t if h == a => inner(t, acc :+ b)
  46.         case h :: t if h == b => inner(t, acc :+ a)
  47.         case h :: t => inner(t, acc :+ h)
  48.       }
  49.       inner(xs.toList, "")
  50.     }
  51.     override def revert(xs: String): String = exec(xs)
  52.   }
  53.  
  54.   case class RotateDirection(dir: Char, by: Int) extends Command with RotateCommand {
  55.     override def exec(xs: String): String = rotate(if (dir == 'R') -by else by, xs.toList).mkString
  56.     override def revert(xs: String): String = rotate(if (dir == 'L') -by else by, xs.toList).mkString
  57.   }
  58.  
  59.   case class RotatePosition(c: Char) extends Command with RotateCommand {
  60.     override def exec(xs: String): String = {
  61.       val i = xs.indexOf(c)
  62.       val by = i + (if (i >= 4) 2 else 1)
  63.       rotate(-by, xs.toList).mkString
  64.     }
  65.     override def revert(xs: String): String = {
  66.       xs.indexOf(c) match {
  67.         case 0 => rotate(1, xs.toList).mkString
  68.         case 1 => rotate(1, xs.toList).mkString
  69.         case 2 => rotate(-2, xs.toList).mkString
  70.         case 3 => rotate(2, xs.toList).mkString
  71.         case 4 => rotate(-1, xs.toList).mkString
  72.         case 5 => rotate(3, xs.toList).mkString
  73.         case 6 => xs
  74.         case 7 => rotate(-4, xs.toList).mkString
  75.       }
  76.     }
  77.   }
  78.  
  79.   case class Move(a: Int, b: Int) extends Command {
  80.     override def exec(xs: String): String = {
  81.       val c = List(xs(a))
  82.       val (h, t) = (xs diff c) splitAt b
  83.       h + c.mkString + t
  84.     }
  85.     override def revert(xs: String): String = {
  86.       val c = List(xs(b))
  87.       val (h, t) = (xs diff c) splitAt a
  88.       h + c.mkString + t
  89.     }
  90.   }
  91.  
  92.   def exec(s: String, cmd: List[String], revert: Boolean): String = {
  93.  
  94.     def getCmd(x: String): Command = x match {
  95.       case pattRv(a, b) => Reverse(a.toInt, b.toInt)
  96.       case pattRp(a) => RotatePosition(a.head)
  97.       case pattRd(a, b) => RotateDirection(a.head.toUpper, b.toInt)
  98.       case pattSp(a, b) => PositionSwap(a.toInt, b.toInt)
  99.       case pattSl(a, b) => LetterSwap(a.head, b.head)
  100.       case pattMv(a, b) => Move(a.toInt, b.toInt)
  101.     }
  102.  
  103.     def inner(xs: String, cmd: List[String]): String = cmd match {
  104.       case Nil => xs
  105.       case h :: t =>
  106.         val command = getCmd(h)
  107.         if (revert) inner(command.revert(xs), t)
  108.         else inner(command.exec(xs), t)
  109.     }
  110.     if (revert) inner(s, cmd.reverse) else inner(s, cmd)
  111.   }
  112.  
  113.   val input = Source.fromFile("day21.txt").getLines.toList
  114.   println(exec("abcdefgh", input, revert = false))
  115.   println(exec("fbgdceah", input, revert = true))
  116.  
  117. }
Advertisement
Add Comment
Please, Sign In to add comment