Skip to content

Instantly share code, notes, and snippets.

@gustavofranke
Last active September 7, 2020 22:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gustavofranke/53df9f5523d53563bd45e48349ed58f9 to your computer and use it in GitHub Desktop.
Save gustavofranke/53df9f5523d53563bd45e48349ed58f9 to your computer and use it in GitHub Desktop.
package cipher
def lowers(xs: String): Int =
xs.filter(x => x >= 'a' && x <= 'z').length
def count(x: Char, xs: String): Int =
xs.toList.filter(x0 => x == x0).length
def positions[A](x: A, xs: List[A]): List[Int] =
for
(x0, i) <- xs.zipWithIndex
if x == x0
yield i
//-- 5.5 The Caesar cipher
def let2int(c: Char): Int = c.toInt - 'a'.toInt
def int2let(n: Int): Char = ('a'.toInt + n).toChar
def shift(n: Int, c: Char): Char = c match
case c0 if c0.isLower => int2let((let2int(c0) + n) % 26)
case _ => c
def encode (n: Int, xs: String): String =
for
x <- xs
yield shift(n, x)
//--- cracking
val table: List[Double] =
List(8.1f, 1.5f, 2.8f, 4.2f, 12.7f, 2.2f, 2.0f, 6.1f, 7.0f,
0.2f, 0.8f, 4.0f, 2.4f, 6.7f, 7.5f, 1.9f, 0.1f, 6.0f,
6.3f, 9.0f, 2.8f, 1.0f, 2.4f, 0.2f, 2.0f, 0.1f)
def percent(n: Int, m: Int): Double = (n.toDouble / m.toDouble) * 100
def freqs(xs: String): List[Double] = {
val n = lowers(xs)
for
x <- ('a' to 'z').toList
yield percent(count(x, xs), n)
}
def chisqr(os: List[Double], es: List[Double]): Double =
(for
(o, e) <- os.zip(es)
yield (math.pow((o - e), 2) / e)).sum.toDouble
def rotate[A](n: Int, xs: List[A]): List[A] = xs.drop(n) ++ xs.take(n)
def crack(xs: String): String = {
val table0: List[Double] = freqs(xs)
val chitab: List[Double] = (0 to 25).toList.map(n => chisqr(rotate(n, table0), table))
val factor: Int = positions(chitab.min, chitab).head
encode(-factor, xs)
}
val test1 = crack("kdvnhoo lv ixq")
val test2 = crack("vscd mywzboroxcsyxc kbo ecopev")
val test3 = crack(encode(3, "haskell"))
val test4 = crack(encode(3, "boxing wizards jump quickly"))
//scala> let2int('a')
//val res1: Int = 0
//
//scala> int2let(0)
//val res2: Char = a
//
//scala> shift(3,'a')
//val res3: Char = d
//
//scala> shift(3,'z')
//val res4: Char = c
//
//scala> shift(-3,'z')
//val res5: Char = w
//
//scala> shift(-3,'c')
//val res6: Char = `
//
//scala> res6
//val res7: Char = `
//
//scala> shift(3,'')
//1 |shift(3,'')
//| ^
// | empty character literal
//
//scala> shift(3,' ')
//val res8: Char =
//
// scala> encode(3,"haskell is fun")
// val res9: String = kdvnhoo lv ixq
//
// scala> encode(-3,"kdvnhoo lv ixq")
// val res10: String = haskell is fun
//
// scala> percent(5,15)
// val res11: Double = 0.0
//
//scala> rotate(3, List(1,2,3,4,5))
//val res5: List[Int] = List(4, 5, 1, 2, 3)
package countdown
trait Show[A]:
def show(a: A): String
enum Op:
case Add, Sub, Mul, Div
given Show[Op]:
def show(a: Op): String = a match
case Op.Add => "+"
case Op.Sub => "-"
case Op.Mul => "*"
case Op.Div => "/"
def valid(op: Op, x: Int, y: Int): Boolean = op match
case Op.Add => true
case Op.Sub => x > y
case Op.Mul => true
case Op.Div => x % y == 0
def apply(op: Op, x: Int, y: Int): Int = op match
case Op.Add => x + y
case Op.Sub => x - y
case Op.Mul => x * y
case Op.Div => x / y
// 9.3 Numeric expressions
enum Expr:
case Val(i: Int)
case App(op: Op, e1: Expr, e2: Expr)
given Show[Expr]:
def show(a: Expr): String = a match
case Expr.Val(n) => summon[Show[Int]].show(n)
case Expr.App(o, l, r) =>
def brak(e: Expr) = e match
case Expr.Val(n) => summon[Show[Int]].show(n)
case e => "(" + show(e) + ")"
brak(l) + summon[Show[Op]].show(o) + brak(r)
given Show[Int]:
def show(a: Int): String = a.toString
//-- For example, 1 + (2 ∗ 3) can be represented as:
val test0 = summon[Show[Expr]].show(Expr.App(Op.Add, Expr.Val(1), Expr.App(Op.Mul, Expr.Val(2), Expr.Val(3)))) //-- "1+(2*3)"
def values(e: Expr): List[Int] = e match
case Expr.Val(n) => List(n)
case Expr.App(_, l, r) => values(l) ++ values(r)
def eval(e: Expr): List[Int] = e match
case Expr.Val(n) => List(n).filter(_ > 0)
case Expr.App(o, l, r) =>
for
x <- eval(l)
y <- eval(r) if valid(o, x, y)
yield apply(o, x, y)
val test1 = eval(Expr.App(Op.Add, Expr.Val(2), Expr.Val(3))) //-- [5]
val test2 = eval(Expr.App(Op.Sub, Expr.Val(2), Expr.Val(3))) //-- []
// 9.4 Combinatorial functions
def subs[A](la: List[A]): List[List[A]] = la match
case Nil => List(List())
case x :: xs =>
val yss: List[List[A]] = subs(xs)
yss ++ yss.map(y => x :: y)
def interleave[A](a: A, la: List[A]): List[List[A]] = (a, la) match
case (x, Nil) => List(List(x))
case (x, y :: ys) => (x :: y :: ys) :: interleave(x, ys).map(is => y :: is)
def perms[A](la: List[A]): List[List[A]] = la match
case Nil => List(List())
case x :: xs => perms(xs).map(as => interleave(x, as)).flatten
val test3 = subs(List(1, 2, 3)) // [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]]
val test4 = interleave(1, List(2, 3, 4)) // [[1,2,3,4],[2,1,3,4],[2,3,1,4],[2,3,4,1]]
val test5 = perms(List(1, 2, 3)) // [[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]]
def choices[A](la: List[A]): List[List[A]] = subs(la).map(slas => perms(slas)).flatten
val test6 = choices(List(1,2,3)) // --[[],[3],[2],[2,3],[3,2],[1],[1,3],[3,1],[1,2],[2,1],[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]]
def solution(e: Expr, ns: List[Int], n: Int): Boolean = choices(ns).contains(values(e)) && eval(e) == List(n)
val e = Expr.App(Op.Add, Expr.Val(1), Expr.Val(50))
val test7 = solution(e, List(1,3,7,10,25,50), 765)
//-- Brute force solution
def split[A](la: List[A]): List[(List[A], List[A])] = la match {
case Nil => Nil
case List(_) => Nil
case x :: xs => (List(x), xs) :: (for
(ls,rs) <- split(xs)
yield (x :: ls, rs))
}
//split (x:xs) = ([x], xs) : [(x:ls,rs) | (ls,rs) <- split xs]
val test8 = split(List(1,2,3,4)) // -- [([1],[2,3,4]),([1,2],[3,4]),([1,2,3],[4])]
def exprs(is: List[Int]): List[Expr] = is match
case Nil => Nil
case List(n) => List(Expr.Val(n))
case ns =>
for
(ls,rs) <- split(ns)
l <- exprs(ls)
r <- exprs(rs)
e <- combine(l, r)
yield e
def combine(l: Expr, r: Expr): List[Expr] = ops.map(o => Expr.App(o, l, r))
def ops = List(Op.Add, Op.Sub, Op.Mul, Op.Div)
def solutions(ns: List[Int], n: Int): List[Expr] =
for
ns0 <- choices(ns)
e <- exprs(ns) if eval(e) == List(n)
yield e
//-- Combining generation and evaluation
type Result = (Expr, Int)
def results(is: List[Int]): List[Result] = is match
case Nil => Nil
case n :: Nil => if n > 0 then List((Expr.Val(n), n)) else Nil
case ns =>
for
(ls, rs) <- split(ns)
lx <- results(ls)
ry <- results(rs)
res <- combine0(lx, ry)
yield res
def combine0(r1: Result, r2: Result): List[Result] = (r1, r2) match
case ((l, x), (r, y)) =>
for
o <- ops if valid0(o, x, y)
yield (Expr.App(o, l, r), apply(o, x, y))
def solutions0(ns: List[Int], n: Int): List[Expr] =
for
ns0 <- choices(ns)
(e,m) <- results(ns0) if m == n
yield e
//-- Exploring algebraic properties
def valid0(op: Op, x: Int, y: Int): Boolean = op match
case Op.Add => x <= y
case Op.Sub => x > y
case Op.Mul => x != 1 && y != 1 && x <= y
case Op.Div => y != 1 && x % y == 0
@main def program: Unit =
// println(s"test0 $test0")
// println(s"test1 $test1")
// println(s"test2 $test2")
// println(s"test3 $test3")
// println(s"test4 $test4")
// println(s"test5 $test5")
// println(s"test6 $test6")
// println(s"test7 $test7")
// println(s"test8 $test8")
// println(s"main ${solutions(List(1,3,7,10,25,50), 765)}")
// println(solutions0(List(1,3,7,10,25,50), 765))
println(solutions0(List(1,3,7,10,25,50), 765).map(summon[Show[Expr]].show))
package hangman
import zio._
import zio.Task
import zio.console._
def putChar(a: => Char): Task[Unit] = Task.succeed(print(a))
//def getChar: Task[Char] = Task.succeed(scala.io.StdIn.readChar)
val hangman: ZIO[Console, Throwable, Unit] =
for
_ <- putStrLn("Think of a word:")
word <- getStrLn
// word <- sgetLine
_ <- putStrLn("Try to guess it:")
_ <- play(word)
yield ()
//val sgetLine: Task[String] =
// for
// x <- getChar
// r <- if x == '\n'
// then (for
// _ <- putChar(x)
// yield "")
// else (for
// _ <- putChar('+')
// xs <- sgetLine
// yield s"$x$xs")
// yield r
//val getCh: Task[Char] = getChar
def play(word: String): ZIO[Console, Throwable, Unit] =
for
_ <- putStrLn("? ")
guess <- getStrLn
_ <- if guess == word then putStrLn("You got it!!")
else (for
_ <- putStrLn(match0(word, guess))
_ <- play(word)
yield ())
yield ()
def match0(xs: String, ys: String): String =
for
x <- xs
yield if ys.contains(x) then x else '-'
object Main extends zio.App:
override def run(args: List[String]): ZIO[zio.ZEnv, Nothing, ExitCode] =
hangman.map(_ => ExitCode.success) orElse ZIO.succeed(ExitCode.failure)
package life
import zio._
import zio.Task
import zio.URIO
import zio.console._
// Screen utilities
val cls: zio.URIO[zio.console.Console, Unit] = putStr("\033[2J")
type Pos = (Int, Int)
def writeat(p: Pos, xs: String): zio.ZIO[zio.console.Console, Nothing, Unit] =
for
_ <- goto(p)
_ <- putStr(xs)
yield ()
import countdown.Show
import countdown.{ given Show[Int] }
def goto(p: Pos): URIO[zio.console.Console, Unit] = p match
case (x, y) => putStr("\033[" + s"${summon[Show[Int]].show(y)};${summon[Show[Int]].show(x)}H")
// Game of life
val width: Int = 10
val height: Int = 10
type Board = List[Pos]
val glider: Board = List((4,2),(2,3),(4,3),(3,4),(4,4))
def showcells(b: Board): zio.ZIO[zio.Has[zio.console.Console.Service], Nothing, Unit] =
ZIO.collectAll(for
p <- b
yield writeat(p, "O")).map(_ => ())
def isAlive(b: Board, p: Pos): Boolean = b.contains(p)
def isEmpty(b: Board, p: Pos): Boolean = ! isAlive(b, p)
def neighbs(p: Pos): List[Pos] = p match
case (x, y) =>
List(
(x - 1, y - 1), (x, y - 1),
(x + 1, y - 1), (x - 1, y),
(x + 1, y), (x - 1, y + 1),
(x, y + 1), (x + 1, y + 1)).map(wrap)
def wrap(p: Pos): Pos = p match
case (x, y) => (((x - 1) % width) + 1, ((y - 1) % height) + 1)
def liveneighbs(b: Board, p: Pos): Int = neighbs(p).filter(np => isAlive(b, np)).length
def survivors(b: Board): List[Pos] =
for
p <- b
if List(2, 3).contains(liveneighbs(b, p))
yield p
def births(b: Board): List[Pos] =
for
p <- rmdups(b.map(neighbs).flatten)
if isEmpty(b, p)
if liveneighbs(b, p) == 3
yield p
def rmdups[A](la: List[A]): List[A] = la match
case Nil => Nil
case x :: xs => x :: rmdups(xs.filter(_ != x))
def nextgen(b: Board): Board = survivors(b) ++ births(b)
def life(b: Board): zio.ZIO[zio.console.Console, Throwable, Unit] =
for
_ <- cls
_ <- showcells(b)
_ <- wait1(500000)
_ <- life(nextgen(b))
yield ()
def wait1(n: Int): Task[Unit] =
ZIO.collectAll(for
_ <- (1 to n).toList
yield ZIO.succeed(())).map(_ => ())
object Main extends zio.App:
override def run(args: List[String]): ZIO[zio.ZEnv, Nothing, ExitCode] =
(for
_ <- life(glider)
yield ExitCode.success) orElse ZIO.succeed(ExitCode.failure)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment