From 67bb27e9f5beec4d8ca0a6c29f045d5f23d6f40f Mon Sep 17 00:00:00 2001 From: Nguyễn Gia Phong Date: Sun, 28 Feb 2021 17:25:57 +0700 Subject: [lang] Reorganize language learning archive --- lang/thinkraku/draft.raku | 298 ++++++++++++++++++++++++++++++++++++ lang/thinkraku/human-seconds.raku | 8 + lang/thinkraku/merry-christmas.raku | 2 + 3 files changed, 308 insertions(+) create mode 100755 lang/thinkraku/draft.raku create mode 100755 lang/thinkraku/human-seconds.raku create mode 100755 lang/thinkraku/merry-christmas.raku (limited to 'lang/thinkraku') diff --git a/lang/thinkraku/draft.raku b/lang/thinkraku/draft.raku new file mode 100755 index 0000000..cfe762d --- /dev/null +++ b/lang/thinkraku/draft.raku @@ -0,0 +1,298 @@ +#!/usr/bin/env raku +# Exercise 2.2.1 +sub sphere-volume(Numeric(Cool) $r) { 4/3 * π * $r³ } +#put sphere-volume('5'); + +# Exercise 3.1 +# Notice the operator precedence +sub rjust(Str $str, Int $width = 70) { ' ' x $width - $str.chars ~ $str } +#put rjust("Larry Wall", 80); + +# Exercise 3.2 +sub print-twice($str) { + put $str; + put $str +} +sub do-twice(&code, $arg) { + code $arg; + code $arg +} +#do-twice(&print-twice, "What's up doc"); +sub do-four(&code, $arg) { do-twice { do-twice &code, $_ }, $arg } + +# Exercise 3.3 +sub grid(Int $rows=2, Int $cols=2, Int $side=4) { + (('+' for 0..$cols).join((' ' for 0..$side).join('-'))~"\n" for 0..$rows) + .join((('|' for 0..$cols).join(' ' x $side*2 + 1)~"\n") x $side) +} +#print grid(4, 4); + +# Exercise 4.2 +sub check-fermat(Int $a, Int $b, Int $c, Int $n) { + return if $n <= 2; + if $a**$n + $b**$n == $c**$n { + put "Holy smokes, Fermat was wrong!" + } else { + put "No, that doesn't work." + } +} + +# Exercise 4.3 +sub is-triangle($a, $b, $c) { ([-] reverse sort $a, $b, $c) < 0 } + +# Exercise 4.4 +sub fibonacci(Int $n, Int $a = 0, Int $b = 1) { + return $a if $n <= 0; #put $a; + fibonacci $n - 1, $b, $a + $b +} +#put fibonacci 20; + +sub hypotenuse($a, $o) { sqrt $a² + $o² } +#put hypotenuse 3, 4; + +# Exercise 5.2 +multi ack(0, Int $n) { $n + 1 } +multi ack(Int $m where * > 0, 0) { ack $m - 1, 1 } +multi ack(Int $m where * > 0, Int $n where * > 0) { + ack $m - 1, ack($m, $n - 1) +} +#put ack 3, 4; + +# Exercise 5.3 +sub is-palindrome(Str $str) { $str eq $str.flip } + +# Exercise 5.4 +sub is-power-of($a, $b) { { $_ == .Int }(log $a, $b) } + +# Exercise 5.5: gcd is a built-in operator + +# Exercise 6.1 +sub my-sqrt($a, $epsilon = 0.000_000_1, $x = $a) { + return $x if abs $x² - $a < $epsilon; + my-sqrt $a, $epsilon, ($x + $a/$x) / 2 +} + +# Exercise 6.2 +sub factorial(Int $n) { [*] 1..$n } +sub estimate-pi { + my $factor = 2 * 2.sqrt / 9801; + sub Srinivasa-Ramanujan($k = 1, $current = 1103, $result = 1103) { + my $next = factorial($k * 4) * (1103 + $k*26390) + / factorial($k)⁴ / 396**($k*4); + return $result + $next if $factor * $next < 10**-15; + Srinivasa-Ramanujan $k + 1, $next, $result + $next; + } + 1 / $factor / Srinivasa-Ramanujan +} +#put abs estimate-pi() - pi; + +sub ducks { map * ~ 'ack' , flat('J'..'N', 'Ou', 'P', 'Qu') } +#put ducks; + +sub count(Str $string, Str $substr, Int $index = 0, Int $result = 0) { + my $i = index $string, $substr, $index; + return $result unless defined $i; + count $string, $substr, $i + 1, $result + 1 +} +#put count 'banana', 'na'; + +sub bubble-sort(@seq is copy) { + my $done; + repeat { + $done = True; + for ^@seq.end -> $i { + if @seq[$i] > @seq[$i+1] { + @seq[$i, $i + 1] .= reverse + $done = False + } + } + } until $done; + @seq +} +#put bubble-sort <4 2 6 5 3 9 1>; + +sub select-sort(@seq is copy) { + for ^@seq.end -> $i { + for $i..@seq.end -> $j { + @seq[$i, $j] .= reverse if @seq[$i] > @seq[$j] + } + } + @seq +} +#put select-sort <4 2 6 5 3 9 1>; + +sub insert-sort(@seq is copy) { + for 1..@seq.end -> $i { + loop (my $j = $i; $j and @seq[$j] < @seq[$j - 1]; $j--) { + @seq[$j, $j - 1] .= reverse + } + } + @seq +} +#put insert-sort <4 2 6 5 3 9 1>; + +# Some simple regexes +#put $/ if "π ≈ $(π)" ~~ /\d**10/; +#put $/ if '1234567890' ~~ /^ <[0..7]>+ $/; +#put $/ if ' Hello, World!' ~~ /\w+/; +#put $/ if 'qaz asdf zxcv' ~~ /<< a \w*/; +#put $/ if 'hmmm ooer' ~~ /<< <[aeiou]> \w*/; +#put $/ if '0621323 0612345678- 0701234567' ~~ /<< 0 <[67]> \d**8 >>/; +#put $/ if 'hMmM OoEr' ~~ /:i << <[aeiou]> \w*/; +#put $/ if 'hmmm ooer' ~~ /(\w)$0/; +#put $1 if 'hmmm ooer' ~~ /(\w) $0 .* ((\w) $0)/; + +sub YYYY-MM-DD(Str $string) { + "$0-$1-$2" if $string ~~ /<< (\d\d\d\d) \- (\d\d) \- (\d\d) >> + / +} +#put YYYY-MM-DD '986-05-19-1700-02-29-1234-11-31-01-10-2000-02-29'; + +# Exercise 7.3 +sub rotate-ascii(Str $string, Int $rotation) { + $string.comb.map({ m/<[A..Z]>/ && chr(65 + ($/.ord + $rotation - 65)%26) || + m/<[a..z]>/ && chr(97 + ($/.ord + $rotation - 97)%26) || + $_ }).join +} +#put rotate-ascii 'cheer', 7; +#put rotate-ascii 'melon', -10; +#put rotate-ascii 'HAL', 1; + +# Exercise 8.1 +#.put if .chars > 20 for '/usr/share/dict/words'.IO.lines; + +# Exercise 8.2 +sub words(&predicate) { '/usr/share/dict/words'.IO.lines.grep(&predicate) } +#.put for words({ not /<[Ee]>/ }); + +# Exercise 8.3 +multi avoids(@letters, @forbidden) { ($_ ∉ @letters for @forbidden).all } +multi avoids(Str $word, Str $forbidden) { avoids $word.comb, $forbidden.comb } +sub least-forbidden(Int $n) { + my %avoids = [$_ => {} for 'a'..'z']; + for '/usr/share/dict/words'.IO.lines.map(~*.lc).unique -> $word { + %avoids{$_}{$word} = True unless defined index $word, $_ for 'a'..'z'; + } + + # Despacito (baby take it slow so we can last long) + [([∩] %avoids{$_}).elems => $_ for combinations('a'..'z', $n)].max.value +} +# Unless run on a supercomputer, there ain't no way +# one has the patience to wait for it to finish. +#say least-forbidden 5; + +# Exercise 8.4 +#.put for words { m:i/^ <[acefhlo]>+ $/ }; + +# Exercise 8.5 +my @uses-all = ; +#.put for words { (defined index $^word, $_ for @uses-all).all }; + +# Exercise 8.6 +sub is-abcdedarian(Str $word) { [lt] $word.lc.comb } +#.put for words &is-abcdedarian; + +# Exercise 8.7 +#.put for words { m/(.) $0 (.) $1 (.) $2/ }; + +# Exercise 8.8 +#.put if [.substr(2), substr($_ + 1, 1), substr($_ + 2, 1, 4), ~($_ + 4)] +# .map(&is-palindrome).all for 100_000..999_996; + +# Exercise 8.9 +sub age-reversible(Int $times) { + for '10'..'90' -> $car { + my $diff = $car - $car.flip; + my @reversible = grep { .flip == $_ - $diff }, $car..'99'; + return @reversible if @reversible == $times + } +} +#put age-reversible(8)[*-3].flip; + +# Exercise 9.1 +multi nested-sum(Numeric $number) { $number } +multi nested-sum(@array) { @array.map(&nested-sum).sum } +#put nested-sum [1, 2, [3, 4], [5, [6, 7]], [[8], [9, [10]]]]; + +# Exercise 9.2 +#put [\+] 1..4; + +# Exercise 9.5 +#put [≤] (1, 2, 2); +#put [≤] (1, 2, 1); + +# Exercise 9.6 +sub is-anagram(Str $this, Str $that) { $this.comb.sort ~~ $that.comb.sort } +#put is-anagram 'this', 'shit'; + +# Exercise 9.7 +sub has-duplicates(@array) { @array.unique != @array } +#put has-duplicates ; + +# Exercise 9.8 +sub birthday-paradox(Int $n, Int $T) { + sum(map { has-duplicates map { 365.25.rand.Int }, ^$n }, ^$T) / $T +} +#put birthday-paradox 23, 10000; + +# Exercise 9.10 +sub bisect(@a, $x, Int $low = 0, Int $high = @a.elems) { + return unless $low < $high; + my $mid = ($low + $high) div 2; + given @a[$mid] cmp $x { + when Less { bisect @a, $x, $mid + 1, $high } + when Same { $mid } + when More { bisect @a, $x, $low, $mid } + } +} + +# Exercise 9.11 +#my @words = '/usr/share/dict/words'.IO.lines; +#put "$_ $(.flip)" if /^(.)$0*$/ ^ defined bisect @words, .flip for @words; + +# Exercise 9.12 +sub interlock(Str $word, @words) { + my ($evens, $odds); + for $word.comb -> $even, $odd = '' { + $evens ~= $even; + $odds ~= $odd + } + bisect(@words, $evens).defined && bisect(@words, $odds).defined +} +#my @words = '/usr/share/dict/words'.IO.lines; +#.put for @words.grep:{ interlock($_, @words) }; + +# Exercise 10.3 +sub hash-duplicates(@array) { + my %hash; + for @array { + return True if %hash{$_}; + %hash{$_} = True + } + False +} +#put hash-duplicates ; + +# Exercise 10.4 +sub rotations { + my %words = '/usr/share/dict/words'.IO.lines.grep(/^ <[a..z]>+ $/).Set; + my @result; + for %words.keys -> $word { + next unless %words{$word}; + (%words{$word}, $_) = False, $word; + my $virgin = True; + loop (tr/a..z/b..za/; $_ cmp $word; tr/a..z/b..za/) { + next unless %words{$_}; + %words{$_} = False; + if $virgin { + $virgin = False; + @result.push([$word, $_]) + } else { + @result[*-1].push($_) + } + } + } + @result +} +.put for rotations; diff --git a/lang/thinkraku/human-seconds.raku b/lang/thinkraku/human-seconds.raku new file mode 100755 index 0000000..610213e --- /dev/null +++ b/lang/thinkraku/human-seconds.raku @@ -0,0 +1,8 @@ +#!/usr/bin/env raku +# Exercise 4.1 +sub MAIN(Int $seconds=240_000) { + put 'Days: ', $seconds div 86400; + put 'Hours: ', $seconds div 3600 % 24; + put 'Minutes: ', $seconds div 60 % 60; + put 'Seconds: ', $seconds % 60 +} diff --git a/lang/thinkraku/merry-christmas.raku b/lang/thinkraku/merry-christmas.raku new file mode 100755 index 0000000..654f5af --- /dev/null +++ b/lang/thinkraku/merry-christmas.raku @@ -0,0 +1,2 @@ +#!/usr/bin/env raku +sub MAIN(Str $name) { put "Merry Christmas, $name!" } -- cgit 1.4.1