forked from lichess-org/lila
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Line.scala
74 lines (62 loc) · 2.19 KB
/
Line.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package lila.puzzle
import play.api.libs.json._
sealed trait Line
case class Node(move: String, lines: Lines) extends Line
case class Win(move: String) extends Line
case class Retry(move: String) extends Line
object Line {
def minDepth(lines: Lines): Int = {
def walk(subs: Vector[(Lines, Int)]): Option[Int] = subs match {
case Vector() => none
case (lines, depth) +: rest => lines match {
case Nil => walk(rest)
case Win(_) :: _ => depth.some
case Retry(_) :: siblings => walk(rest :+ (siblings -> depth))
case Node(_, children) :: siblings =>
walk(rest :+ (siblings -> depth) :+ (children -> (depth + 1)))
}
}
(1 + ~(walk(Vector(lines -> 1)))) / 2
}
def solution(lines: Lines): List[String] = {
def getIn(lines: Lines, path: List[String]): Lines = path match {
case Nil => lines
case head :: rest => lines collectFirst {
case Node(move, lines) if move == head => getIn(lines, rest)
case w @ Win(move) if move == head => List(w)
case r @ Retry(move) if move == head => List(r)
} getOrElse Nil
}
def loop(paths: List[List[String]]): List[String] = paths match {
case Nil => Nil
case path :: siblings => getIn(lines, path) match {
case List(Win(m)) => path :+ m
case List(Retry(_)) => loop(siblings)
case ahead => ahead.collectFirst {
case Win(m) => path :+ m
} | {
val children = ahead collect { case Node(m, ls) => path :+ m }
loop(siblings ::: children)
}
}
}
lines.collectFirst {
case Win(move) => List(move)
} | loop(lines collect {
case Node(move, _) => List(move)
})
}
def toString(lines: Lines, level: Int = 0): String = {
val indent = ". " * level
lines map {
case Win(move) => s"$indent$move win"
case Retry(move) => s"$indent$move retry"
case Node(move, more) => s"$indent$move\n${toString(more, level + 1)}"
} mkString "\n"
}
def toJson(lines: Lines): JsObject = JsObject(lines map {
case Win(move) => move -> JsString("win")
case Retry(move) => move -> JsString("retry")
case Node(move, more) => move -> toJson(more)
})
}