Last active
September 7, 2020 22:42
-
-
Save gustavofranke/53df9f5523d53563bd45e48349ed58f9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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