Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.text.DecimalFormat
- import scala.io.StdIn._
- import scala.util.matching.Regex
- object Main {
- import Parsers._
- import Model._
- def main(args: Array[String]): Unit = {
- def number: Parser[Expr] = regex("\\d+".r).map(a => Num(a.toInt))
- def rand: Parser[Expr] = regex("d\\d+".r).map(a => Rand(a.tail.toInt))
- def literal: Parser[Expr] = number | rand
- def surround[A](p: Parser[A]): Parser[A] = string("(") ~> p ~< string(")")
- def expr: Parser[Expr] = (gtExpr ~ many(string(">") ~ gtExpr)).map(a => listToBinary(a._1, a._2))
- def gtExpr: Parser[Expr] = (termExpr ~ many(string("+") ~ termExpr | string("-") ~ termExpr)).map(a => listToBinary(a._1, a._2))
- def termExpr: Parser[Expr] = (factorExpr ~ many(string("*") ~ factorExpr)).map(a => listToBinary(a._1, a._2))
- def factorExpr: Parser[Expr] = literal | surround(expr)
- val s = readLine()
- printDistribution(eval(run(s, expr).get))
- }
- def listToBinary(expr: Expr, operatorsWithExprs: List[(String, Expr)]): Expr = {
- operatorsWithExprs.foldLeft[Expr](expr) { case (acc, (op, e)) =>
- op match {
- case "*" => Mult(acc, e)
- case "+" => Plus(acc, e)
- case "-" => Minus(acc, e)
- case ">" => GT(acc, e)
- }
- }
- }
- def printDistribution(distribution: Map[Int, Double]): Unit = {
- distribution.toList.sortBy(_._1).foreach { case (k, v) =>
- println(s"$k ${new DecimalFormat("0.00").format(v*100)}")
- }
- }
- }
- object Parsers {
- def run[A](s: String, p: Parser[A]): Option[A] = p.repr(s) match {
- case (Some(a), "") => Some(a)
- case _ => None
- }
- def runDebug[A](s: String, p: Parser[A]): (Option[A], String) = p.repr(s) match {
- case (result, s1) => (result, s1)
- }
- case class Parser[A](repr: String => (Option[A], String)) {
- def map[B](f: A => B): Parser[B] = Parser(
- s => this.repr(s) match {
- case (None, _) => (None, s)
- case (Some(a), s1) => (Some(f(a)), s1)
- }
- )
- }
- def sequence[A, B](p1: Parser[A], p2: =>Parser[B]): Parser[(A, B)] = {
- Parser(
- s => p1.repr(s) match {
- case (None, _) => (None, s)
- case (Some(a), s1) => p2.repr(s1) match {
- case (None, _) => (None, s)
- case (Some(b), s2) => (Some((a, b)), s2)
- }
- }
- )
- }
- def many[A](p: Parser[A]): Parser[List[A]] = {
- sequence(p, many(p)).map(a => a._1 :: a._2) | succeed(List.empty)
- }
- def many1[A](p: Parser[A]): Parser[List[A]] = {
- sequence(p, many(p)).map(a => a._1 :: a._2)
- }
- def disjunction[A](p1: Parser[A], p2: =>Parser[A]): Parser[A] =
- Parser(
- s => p1.repr(s) match {
- case (None, _) => p2.repr(s) match {
- case (None, _) => (None, s)
- case (Some(a), s1) => (Some(a), s1)
- }
- case (Some(a), s1) => (Some(a), s1)
- }
- )
- def succeed[A](a: A): Parser[A] = Parser(s => (Some(a), s))
- def regex(r: Regex): Parser[String] =
- Parser(
- s => r.findPrefixOf(s) match {
- case None => (None, s)
- case Some(a) => (Some(a), s.drop(a.length))
- }
- )
- def string(r: String): Parser[String] =
- Parser(
- s => if (s.startsWith(r)) (Some(r), s.drop(r.length)) else (None, s)
- )
- implicit class Ops[A](parser: Parser[A]) {
- def ~[B](other: =>Parser[B]): Parser[(A, B)] = sequence(parser, other)
- def ~>[B](other: =>Parser[B]): Parser[B] = sequence(parser, other).map(a => a._2)
- def ~<[B](other: =>Parser[B]): Parser[A] = sequence(parser, other).map(a => a._1)
- def |(other: =>Parser[A]): Parser[A] = disjunction(parser, other)
- }
- }
- object Model {
- sealed abstract class Expr
- case class Num(a: Int) extends Expr
- case class Rand(a: Int) extends Expr
- case class Mult(a: Expr, b: Expr) extends Expr
- case class Plus(a: Expr, b: Expr) extends Expr
- case class Minus(a: Expr, b: Expr) extends Expr
- case class GT(a: Expr, b: Expr) extends Expr
- def eval(e: Expr): Map[Int, Double] = {
- e match {
- case Num(a) => Map(a -> 1.0)
- case Rand(a) => Vector.tabulate(a)(i => (i + 1) -> 1.0 / a).toMap
- case Mult(a, b) => combineDistributions(eval(a), eval(b), _ * _)
- case Plus(a, b) => combineDistributions(eval(a), eval(b), _ + _)
- case Minus(a, b) => combineDistributions(eval(a), eval(b), _ - _)
- case GT(a, b) => combineDistributions(eval(a), eval(b), (x, y) => if (x > y) 1 else 0)
- }
- }
- def combineDistributions(a: Map[Int, Double], b: Map[Int, Double], op: (Int, Int) => Int): Map[Int, Double] = {
- var res = Map.empty[Int, Double]
- val denormCoef = 0.0
- for ((k1, v1) <- a) {
- for ((k2, v2) <- b) {
- val k = op(k1, k2)
- val v = v1 * v2
- res += k -> (v + res.getOrElse(k, 0.0))
- }
- }
- res
- }
- }
Add Comment
Please, Sign In to add comment