diff options
| author | Archargelod <archargelod@gmail.com> | 2024-03-08 19:02:07 +0800 |
|---|---|---|
| committer | Archargelod <archargelod@gmail.com> | 2024-03-08 19:02:07 +0800 |
| commit | c45f2d8a7ae3836921747c832d2bfe9db7cc9aa9 (patch) | |
| tree | cea6fb0f51440f00210ab68d018e334c92bc7ef5 | |
| parent | 510484bb98b0d2413f8c09c0a827e91b992d2533 (diff) | |
| download | perlweeklychallenge-club-c45f2d8a7ae3836921747c832d2bfe9db7cc9aa9.tar.gz perlweeklychallenge-club-c45f2d8a7ae3836921747c832d2bfe9db7cc9aa9.tar.bz2 perlweeklychallenge-club-c45f2d8a7ae3836921747c832d2bfe9db7cc9aa9.zip | |
weeks 27-40, 259 in Nim
43 files changed, 1299 insertions, 0 deletions
diff --git a/challenge-027/archargelod/README b/challenge-027/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-027/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-027/archargelod/nim/ch_1.nim b/challenge-027/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..15e65d5812 --- /dev/null +++ b/challenge-027/archargelod/nim/ch_1.nim @@ -0,0 +1,40 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/options + +type + Point = tuple[x, y: float] + Line = (Point, Point) + +func getIntersection(l1, l2: Line): Option[Point] = + ## can't handle co-linear lines + let + ix: Line = + ((l1[1].x - l1[0].x, l1[1].y - l1[0].y), (l2[1].x - l2[0].x, l2[1].y - l2[0].y)) + s: float = + (-ix[0].y * (l1[0].x - l2[0].x) + ix[0].x * (l1[0].y - l2[0].y)) / + (-ix[1].x * ix[0].y + ix[0].x * ix[1].y) + t: float = + (ix[1].x * (l1[0].y - l2[0].y) - ix[1].y * (l1[0].x - l2[0].x)) / + (-ix[1].x * ix[0].y + ix[0].x * ix[1].y) + + if s >= 0 and s <= 1 and t >= 0 and t <= 1: + # Collision detected + return some((l1[0].x + (t * ix[0].x), l1[0].y + (t * ix[0].y))) + + none(Point) + +when isMainModule: + import std/unittest + + const + TestLines = [ + ((0.0, 0.0), (10.0, 10.0)), ((10.0, 0.0), (0.0, 10.0)), + ((0.0, 0.0), (10.0, 10.0)), ((10.0, 0.0), (6.0, 4.0)), + ] + Expected = [some(Point (5.0, 5.0)), none(Point)] + + suite "Intersection of two lines": + test "intersection detected": + check getIntersection(TestLines[0], TestLines[1]) == Expected[0] + test "no intersection": + check getIntersection(TestLines[2], TestLines[3]) == Expected[1] diff --git a/challenge-027/archargelod/nim/ch_2.nim b/challenge-027/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..2cd2eec204 --- /dev/null +++ b/challenge-027/archargelod/nim/ch_2.nim @@ -0,0 +1,59 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +type Hist*[T] = object + # object fields without `*` are private and can't be accesed + h_val: T + h_history: seq[T] + +func initHist*[T](value: T): Hist[T] = + Hist[T](h_val: value) + +func `history`*[T](obj: Hist[T]): seq[T] = + ## getter for previous values of a historical type + obj.h_history + +func `val`*[T](obj: Hist[T]): T = + ## getter for current value of a historical type + obj.h_val + +func `val=`*[T](obj: var Hist[T], value: T) = + ## setter for value of a historical type + if obj.h_val != value: + obj.h_history.add obj.h_val + obj.h_val = value + +func `clearHistory`*[T](obj: var Hist[T]) = + ## clear previous values of a historical type + obj.h_history.setLen(0) + +func `$`*[T](obj: Hist[T]): string = + $obj.h_val + +when isMainModule: + import std/unittest + + suite "Historical values": + test "basic example": + var x = initHist[int](10) + x.val = 20 + x.val = x.val - 5 + + check x.val == 15 + check x.history == [10, 20] + + test "history doesn't change if value didn't change": + var x = initHist[int](69) + x.val = 69 + x.val = 420 + x.val = 420 + + check x.val == 420 + check x.history == [69] + + test "clearHistory clears the history": + var x = initHist[int](42) + x.val = x.val + 1 + x.clearHistory() + x.val = 133 + + check x.val == 133 + check x.history == [43] diff --git a/challenge-028/archargelod/README b/challenge-028/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-028/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-028/archargelod/nim/ch_1.nim b/challenge-028/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..d2d316087d --- /dev/null +++ b/challenge-028/archargelod/nim/ch_1.nim @@ -0,0 +1,17 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[mimetypes, os] + +proc contentsVerbose(filename: string): string = + if not fileExists(filename): + raise newException(IOError, "'" & filename & "' does not exist.") + + let + db = newMimetypes() + (_, name, ext) = filename.splitFile() + # couldn't think of other way to check contents without reading the file ¯\_(0_0)_/¯ + mimetype = db.getMimetype(ext, "data") + + "The file '" & name & ext & "' is of type '" & mimetype & "'." + +when isMainModule: + echo contentsVerbose("/usr/share/mime/image/gif.xml") diff --git a/challenge-028/archargelod/nim/ch_2.nim b/challenge-028/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..fede825f37 --- /dev/null +++ b/challenge-028/archargelod/nim/ch_2.nim @@ -0,0 +1,23 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[times, strutils] + +const + Dg_On = "•" + Dg_Off = "·" + +proc displayBinaryClock*() = + var columns: array[6, array[4, bool]] + + for colId, decDigit in format(now(), "HHmmss"): + for bitId, bit in (decDigit.ord - '0'.ord).toBin(4): + if bit == '1': + columns[colId][bitId] = true + + for y in columns[0].low .. columns[0].high: + for x in columns.low .. columns.high: + stdout.write if columns[x][y]: Dg_On else: Dg_Off + stdout.write '\n' + stdout.flushFile() + +when isMainModule: + displayBinaryClock() diff --git a/challenge-029/archargelod/README b/challenge-029/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-029/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-029/archargelod/nim/ch_1.nim b/challenge-029/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..6a21d7795b --- /dev/null +++ b/challenge-029/archargelod/nim/ch_1.nim @@ -0,0 +1,26 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[parseutils, strutils] + +proc expandBraces(input: string): string = + let start = input.skipUntil('{') + let finish = start + input.skipUntil('}', start) + + let (before, after) = (input[0..<start], input[finish+1..^1]) + for middle in input[start+1..<finish].split(','): + result.add before & middle & after & '\n' + +when isMainModule: + import std/unittest + + const + Test = "Perl {Daily,Weekly,Monthly,Yearly} Challenge" + Expected = """ +Perl Daily Challenge +Perl Weekly Challenge +Perl Monthly Challenge +Perl Yearly Challenge +""" + + suite "Brace expansion": + test "": + check Test.expandBraces() == Expected diff --git a/challenge-029/archargelod/nim/ch_2.nim b/challenge-029/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..7f52f5c6dd --- /dev/null +++ b/challenge-029/archargelod/nim/ch_2.nim @@ -0,0 +1,38 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off + +# we can add C code directly to Nim source file with emit pragma +{.emit: """ + char* hello_world() { + return "Hello, World!"; + } +""".} + +# this is a thin wrapper over C function with a new name +proc hello_C: cstring {.importc: "hello_world".} + +# https://www.gnu.org/software/libc/manual/html_node/Obfuscating-Data.html +proc memfrob(mem: pointer, length: csize_t): pointer {.importc.} + +# a proper wrapper +proc obfuscate*[T: char | byte](arr: var openarray[T]) = + ## Reversibly obfuscates data. Each byte is bitwise xor-ed + ## with the binary pattern 00101010 (hexadecimal 0x2A) + discard memfrob(arr.addr, csize_t(arr.len)) + +when isMainModule: + import std/unittest + + const + Greeting = "Hello, World!" + Plain = "abcdefgh" + Obfuscated = "KHINOLMB" + + suite "Calling C functions": + test "Custom C function": + check hello_C() == Greeting + test "GNU libc (glibc) function": + var a = Plain + a.obfuscate() + check a == Obfuscated + a.obfuscate() + check a == Plain diff --git a/challenge-030/archargelod/README b/challenge-030/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-030/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-030/archargelod/nim/ch_1.nim b/challenge-030/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..f81c8d6381 --- /dev/null +++ b/challenge-030/archargelod/nim/ch_1.nim @@ -0,0 +1,11 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/times + +proc main() = + for year in 2019..2100: + let weekDay = getDayOfWeek(31, mDec, year) + let day = 31 - (weekDay.ord + 1) mod 7 + echo day, " ", mDec, " ", year, " is Sunday" + +when isMainModule: + main() diff --git a/challenge-030/archargelod/nim/ch_2.nim b/challenge-030/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..69c01c6a55 --- /dev/null +++ b/challenge-030/archargelod/nim/ch_2.nim @@ -0,0 +1,44 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off + +proc sorted(a: array[3, int]): array[3, int] = + result = a + if result[1] < result[0]: + swap(result[1], result[0]) + + if result[2] < result[1]: + swap(result[2], result[1]) + if result[1] < result[0]: + swap(result[1], result[0]) + +proc possibleSeriesOf3(val: int): seq[array[3, int]] = + for n1 in countUp(2, val, 2): + var n = [n1, val - n1, 0] + while n[1] > n[2]: + inc n[2] + dec n[1] + let newSeries = n.sorted() + if newSeries notin result: + result.add newSeries + +when isMainModule: + import std/unittest + + const + Expected = [ + [1, 2, 9], + [2, 2, 8], + [2, 3, 7], + [2, 4, 6], + [2, 5, 5], + [1, 4, 7], + [3, 4, 5], + [4, 4, 4], + [1, 5, 6], + [3, 3, 6], + [1, 3, 8], + [1, 1, 10], + ] + + suite "Sums of 3 numbers equal to 12": + test "12 possible series": + check possibleSeriesOf3(12) == Expected diff --git a/challenge-031/archargelod/README b/challenge-031/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-031/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-031/archargelod/nim/ch_1.nim b/challenge-031/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..44186b3e54 --- /dev/null +++ b/challenge-031/archargelod/nim/ch_1.nim @@ -0,0 +1,17 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off + +proc isDivisionByZero(num, denom: int): bool = + num / denom == Inf + +when isMainModule: + import std/unittest + + const + Test = [(15, 0), (15, 5)] + Expected = [true, false] + + suite "Division by zero": + test "Example 1": + check isDivisionByZero(Test[0][0], Test[0][1]) == Expected[0] + test "Example 2": + check isDivisionByZero(Test[1][0], Test[1][1]) == Expected[1] diff --git a/challenge-032/archargelod/README b/challenge-032/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-032/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-032/archargelod/nim/ch_1.nim b/challenge-032/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..70d030f3e2 --- /dev/null +++ b/challenge-032/archargelod/nim/ch_1.nim @@ -0,0 +1,37 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[parseutils, tables] + +proc countUniqLines(input: string): CountTable[string] = + var index = 0 + while index < input.len: + let lineLength = input.skipUntil('\n', index) + let line = input[index ..< index+lineLength] + result.inc(line) + + index += lineLength + 1 + +when isMainModule: + import std/unittest + + const + Expected = {"apple": 3, "banana": 1, "cherry": 2} + Test = """ +apple +banana +apple +cherry +cherry +apple""" + + template checkTable(table, tuples: typed) = + for (val, cnt) in tuples: + check table[val] == cnt + + when defined(csv): + for val, cnt in countUniqLines(Test): + echo val, ',', cnt + else: + suite "Count instances": + test "Example 1": + checkTable(countUniqLines(Test), Expected) + diff --git a/challenge-032/archargelod/nim/ch_2.nim b/challenge-032/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..ecdc9c099b --- /dev/null +++ b/challenge-032/archargelod/nim/ch_2.nim @@ -0,0 +1,23 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[strutils] + +proc barGraph(valuePairs: openarray[(string, int)], magnitude = 1): string = + const minOffset = 8 + for (label, value) in valuePairs: + let offset = ' '.repeat(max(0, minOffset - label.len)) + result &= label & offset & " | " & '#'.repeat(value * magnitude) & '\n' + +when isMainModule: + import std/unittest + + const + Test = {"apple": 3, "banana": 1, "cherry": 2} + Expected = """ +apple | ############ +banana | #### +cherry | ######## +""" + + suite "ASCII bar chart": + test "Example 1": + check barGraph(Test, 4) == Expected diff --git a/challenge-033/archargelod/README b/challenge-033/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-033/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-033/archargelod/nim/ch_1.nim b/challenge-033/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..211e001742 --- /dev/null +++ b/challenge-033/archargelod/nim/ch_1.nim @@ -0,0 +1,20 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[strutils, tables, streams] + +proc countLetters(filename: string): CountTable[char] = + let f = newFileStream(filename) + defer: + f.close() + while not f.atEnd(): + let c = f.readChar() + if c in Letters: + result.inc(c) + +proc main = + var counts = countLetters("/usr/share/dict/words") + counts.sort() + for c, cnt in counts: + echo c, ": ", cnt + +when isMainModule: + main() diff --git a/challenge-033/archargelod/nim/ch_2.nim b/challenge-033/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..f93e0e00d3 --- /dev/null +++ b/challenge-033/archargelod/nim/ch_2.nim @@ -0,0 +1,22 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[strutils, strformat] + +proc printMultiplicationTable(max: Positive) = + # header + stdout.write " x|" + for i in 1..max: stdout.write &"{i:4}" + stdout.write '\n' + echo "---+", '-'.repeat(max*4) + # body + for i in 1..max: + stdout.write &"{i:3}|" + for j in 1..max: + if j < i: + stdout.write ' '.repeat(4) + else: + stdout.write &"{i*j:4}" + + stdout.write '\n' + +when isMainModule: + printMultiplicationTable(11) diff --git a/challenge-034/archargelod/README b/challenge-034/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-034/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-034/archargelod/nim/ch_1.nim b/challenge-034/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..4598f9e0ee --- /dev/null +++ b/challenge-034/archargelod/nim/ch_1.nim @@ -0,0 +1,20 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off + +when isMainModule: + import std/unittest + + const + Test = "Write a program that demonstrates using hash slices and/or array slices." + Expected = "Here's a program that demonstrates using the array slices." + + suite "Hash and/or array slices": + test "Example 1": + var res = Test + res[0..4] = "Here's" + res[41..58] = "the" + check res == Expected + test "Example 2": + let res = "Here's" & Test[5..39] & "the" & Test[58..^1] + check res == Expected + + diff --git a/challenge-034/archargelod/nim/ch_2.nim b/challenge-034/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..7ce993f04e --- /dev/null +++ b/challenge-034/archargelod/nim/ch_2.nim @@ -0,0 +1,24 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/tables + +var Procedures = { + "-h": func(): int = 0, + "-g": func(): int = 1, +}.toTable + +proc dispatch(s: string): int = + Procedures[s]() + +when isMainModule: + import std/[unittest, random] + + const + Test = ["-h", "-g"] + Expected = [1, 0] + + suite "Dispatch table": + test "Execute function from table at runtime": + check dispatch(Test[rand(1)]) == Expected[0] + test "Execute different function from table at runtime": + check dispatch(Test[rand(1)]) == Expected[1] + diff --git a/challenge-035/archargelod/README b/challenge-035/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-035/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-035/archargelod/nim/ch_1.nim b/challenge-035/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..660488a451 --- /dev/null +++ b/challenge-035/archargelod/nim/ch_1.nim @@ -0,0 +1,110 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[strutils, tables] + +const + MorseDot = "1" + MorseDash = "111" + MorseGap = "0" + MorseCharGap = "00" # CharGap is Gap + Extra 2 zeroes = 3 zeroes total + MorseWordGap = "0000" # WordGap is Gap + CharGap + Extra 4 zeroes = 7 zeroes total + + CharToMorse = { + '0': "-----", + '1': ".----", + '2': "..---", + '3': "...--", + '4': "....-", + '5': ".....", + '6': "-....", + '7': "--...", + '8': "---..", + '9': "----.", + 'a': ".-", + 'b': "-...", + 'c': "-.-.", + 'd': "-..", + 'e': ".", + 'f': "..-.", + 'g': "--.", + 'h': "....", + 'i': "..", + 'j': ".---", + 'k': "-.-", + 'l': ".-..", + 'm': "--", + 'n': "-.", + 'o': "---", + 'p': ".--.", + 'q': "--.-", + 'r': ".-.", + 's': "...", + 't': "-", + 'u': "..-", + 'v': "...-", + 'w': ".--", + 'x': "-..-", + 'y': "-.--", + 'z': "--..", + '.': ".-.-.-", + ',': "--..--", + '?': "..--..", + '!': "-.-.--", + '-': "-....-", + '/': "-..-.", + '@': ".--.-.", + '(': "-.--.", + ')': "-.--.-", + }.toTable() + +proc normalizeWhitespace(input: string): string = + var lastCharIsSpace = false + for c in input: + if c in Whitespace: + if lastCharIsSpace: + continue + else: + result.add c + lastCharIsSpace = true + else: + result.add c + lastCharIsSpace = false + +proc toBinaryMorse*(input: string): seq[byte] = + var binString = "" + let input = input.strip().normalizeWhitespace() + for c in input: + if c == ' ': + binString.add MorseWordGap + continue + + let c = c.toLowerAscii() + if c in CharToMorse: + let morse = CharToMorse[c] + for c in morse: + case c + of '.': binString.add MorseDot + of '-': binString.add MorseDash + else: raiseAssert("Invalid morse character:" & c) + binString.add MorseGap + binString.add MorseCharGap + + binString.setLen(binString.len - MorseGap.len - MorseCharGap.len) + + for i in countUp(0, binString.high, 8): + var section = binString[i..min(i+7, binString.high)] + if section.len < 8: + section &= '0'.repeat(8 - section.len) + result.add cast[byte](parseBinInt(section)) + +when isMainModule: + import std/[unittest] + + const + Test = " Some test sTriNg " + Expected = [168'u8, 238, 227, 184, 128, 226, 42, 56, 10, 142, 46, 138, 58, 59, 160] + + suite "Encode binary morse code": + test "Encode simple message": + check toBinaryMorse(Test) == Expected + test "Save message as file for part 2": + writeFile("message", toBinaryMorse(Test)) diff --git a/challenge-035/archargelod/nim/ch_2.nim b/challenge-035/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..a09460359f --- /dev/null +++ b/challenge-035/archargelod/nim/ch_2.nim @@ -0,0 +1,109 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[strutils, tables, parseutils, streams] + +const + MorseToChar = { + "-----" : '0', + ".----" : '1', + "..---" : '2', + "...--" : '3', + "....-" : '4', + "....." : '5', + "-...." : '6', + "--..." : '7', + "---.." : '8', + "----." : '9', + ".-" : 'a', + "-..." : 'b', + "-.-." : 'c', + "-.." : 'd', + "." : 'e', + "..-." : 'f', + "--." : 'g', + "...." : 'h', + ".." : 'i', + ".---" : 'j', + "-.-" : 'k', + ".-.." : 'l', + "--" : 'm', + "-." : 'n', + "---" : 'o', + ".--." : 'p', + "--.-" : 'q', + ".-." : 'r', + "..." : 's', + "-" : 't', + "..-" : 'u', + "...-" : 'v', + ".--" : 'w', + "-..-" : 'x', + "-.--" : 'y', + "--.." : 'z', + ".-.-.-": '.', + "--..--": ',', + "..--..": '?', + "-.-.--": '!', + "-....-": '-', + "-..-." : '/', + ".--.-.": '@', + "-.--." : '(', + "-.--.-": ')', + }.toTable() + +proc parseBinaryMorse(data: openarray[byte]): string = + var binString = "" + for b in data: + binString &= cast[int](b).toBin(8) + binString = binString.strip(chars = {'0'}) # might be unnecessa |
