diff options
| author | Archargelod <archargelod@gmail.com> | 2024-02-21 01:33:32 +0800 |
|---|---|---|
| committer | Archargelod <archargelod@gmail.com> | 2024-02-21 01:33:32 +0800 |
| commit | 77f7f91c73773aa6cfd2713dea32c705a1971b58 (patch) | |
| tree | 368b987ea819a1083930390e2cef19151827c4d6 | |
| parent | ddd42e0db3017a5ec3108d09efba477f19e7f04b (diff) | |
| download | perlweeklychallenge-club-77f7f91c73773aa6cfd2713dea32c705a1971b58.tar.gz perlweeklychallenge-club-77f7f91c73773aa6cfd2713dea32c705a1971b58.tar.bz2 perlweeklychallenge-club-77f7f91c73773aa6cfd2713dea32c705a1971b58.zip | |
Weeks 5-13, 257 in Nim
29 files changed, 764 insertions, 0 deletions
diff --git a/challenge-005/archargelod/README b/challenge-005/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-005/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-005/archargelod/nim/ch_1.nim b/challenge-005/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..43f865180d --- /dev/null +++ b/challenge-005/archargelod/nim/ch_1.nim @@ -0,0 +1,30 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[strutils, algorithm, sets] + +let dict = block: + var tmp: Hashset[string] + for word in lines "/usr/share/dict/words": + tmp.incl word + tmp + +proc allAnagrams(word: string): seq[string] = + var tmp = word + while tmp.nextPermutation(): + let word = tmp.join() + if word in dict: result.add word + + tmp = word + while tmp.prevPermutation(): + let word = tmp.join() + if word in dict: result.add word + +when isMainModule: + import std/unittest + + const + TestWord1 = "god" + ExpectedAnagrams1 = sorted ["dog"] + + suite "All anagrams for word": + test "should return all anagrams for \'god\'": + check sorted(allAnagrams(TestWord1)) == ExpectedAnagrams1 diff --git a/challenge-005/archargelod/nim/ch_2.nim b/challenge-005/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..dbe7b063fe --- /dev/null +++ b/challenge-005/archargelod/nim/ch_2.nim @@ -0,0 +1,16 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[algorithm, strutils, strformat, tables] + +proc mostAnagramWord(dictfile: string): (seq[char], int) = + var counts: CountTable[seq[char]] + for word in lines dictFile: + counts.inc word.sorted() + + counts.largest + +proc main = + let (val, cnt) = mostAnagramWord("/usr/share/dict/words") + echo &"Word with most anagrams is '{val.join()}' with count of {$cnt} possible anagrams." + +when isMainModule: + main() diff --git a/challenge-006/archargelod/README b/challenge-006/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-006/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-006/archargelod/nim/ch_1.nim b/challenge-006/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..0e1c252ea3 --- /dev/null +++ b/challenge-006/archargelod/nim/ch_1.nim @@ -0,0 +1,33 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off + +type + NumberRange = tuple + val, l: int + +func `$`(s: NumberRange): string = + if s.l == 0: + $s.val + elif s.l == 1: + $s.val & ',' & $(s.val + s.l) + else: + $s.val & '-' & $(s.val + s.l) + +func compactNumString*(numbers: openarray[int]): string = + if numbers.len < 1: return result + + var range: NumberRange = (numbers[0], 0) + for i, num in numbers[1..^1]: + if num == range.val + range.l + 1: + inc range.l + else: + result &= $range & ',' + range = (num, 0) + + result &= $range + +when isMainModule: + import std/unittest + + suite "Compact number lists": + test "Example 1": + check compactNumString([1,2,3,4,9,10,14,15,16]) == "1-4,9,10,14-16" diff --git a/challenge-006/archargelod/nim/ch_2.nim b/challenge-006/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..7f788da601 --- /dev/null +++ b/challenge-006/archargelod/nim/ch_2.nim @@ -0,0 +1,11 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import pkg/mapm # `$ nimble install mapm` + +let approxR* = pow(640_320'M, 3) + 744'M - divide(75'M, 100_000_000_000_000'M, 16) + +when isMainModule: + import std/unittest + + suite "Ramanujan's constant": + test "32-digit approximation": + check $approxR == "262537412640768743.99999999999925" diff --git a/challenge-007/archargelod/README b/challenge-007/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-007/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-007/archargelod/nim/ch_1.nim b/challenge-007/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..13b3d016c1 --- /dev/null +++ b/challenge-007/archargelod/nim/ch_1.nim @@ -0,0 +1,21 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off + +proc sumOfDigits(n: int): int = + for d in $n: + result += d.ord - '0'.ord + +proc allNivenNumbers(range: HSlice[int, int]): seq[int] = + for n in max(1, range.a) .. range.b: + if n mod sumOfDigits(n) == 0: + result.add n + +when isMainModule: + import std/[unittest] + + const Expected = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 18, 20, 21, 24, 27, 30, 36, 40, 42, 45, 48, 50 + ] + + suite "Niven numbers": + test "niven numbers 0 to 50": + check allNivenNumbers(0 .. 50) == Expected diff --git a/challenge-007/archargelod/nim/ch_2.nim b/challenge-007/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..ef95601c09 --- /dev/null +++ b/challenge-007/archargelod/nim/ch_2.nim @@ -0,0 +1,87 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[tables, deques] + +type Node = ref object + word: string + neighbours: seq[Node] + +func hammingDist(s1, s2: string): int = + if s1.len != s2.len: + raise newException(ValueError, "Both words should be the same length.") + for i, c in s1: + if c != s2[i]: + inc result + +func shortestPath(start: Node, finish: string): seq[string] = + var paths: Deque[seq[Node]] + paths.addFirst @[start] + + while paths.len > 0: + var + path = paths.popLast() + last = path[^1] + + if last.word == finish: + for n in path: + result.add n.word + return result + + for neighbour in last.neighbours: + if neighbour notin path: + paths.addLast path & neighbour + + raise newException(ValueError, "No path exists.") + +func makeMap(words: sink seq[string], start: string): Node = + var nodes: Table[string, Node] + + for word in words: + nodes[word] = Node(word: word) + + for i, word in words: + for j, word2 in words: + if i == j: + continue + if hammingDist(word, word2) == 1: + nodes[word].neighbours.add nodes[word2] + + nodes[start] + +proc makeMap(dictFile, start: string): Node = + var words: seq[string] + for word in lines dictFile: + words.add word + makeMap(words, start) + +proc findShortestWordLadder*( + start, finish: string, dict: string | seq[string] + ): seq[string] = + ## dict should be the path to dictionary file + ## with words separated by newlines or `seq[string]` of these words + ## dictionary words should be the same length + ## returns empty `seq[string]` on error. + try: + var startNode = makeMap(dict, start) + result = startNode.shortestPath(finish) + except ValueError: + return @[] + +when isMainModule: + import std/unittest + + const + Words = @["cold", "cord", "core", "care", "card", "ward", "warm"] + WrongLengthWords = @["cold", "cord", "core", "caress"] + NoPathsWords = @["cold", "rule", "core", "bear"] + Start = "cold" + Finish = "warm" + Expected = @["cold", "cord", "card", "ward", "warm"] + Empty: seq[string] = @[] + + suite "Word Ladders": + test "cold -> warm": + check findShortestWordLadder(Start, Finish, Words) == Expected + test "wrong length": + check findShortestWordLadder(Start, Finish, WrongLengthWords) == Empty + test "no possible paths": + check findShortestWordLadder(Start, Finish, NoPathsWords) == Empty diff --git a/challenge-008/archargelod/README b/challenge-008/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-008/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-008/archargelod/nim/ch_1.nim b/challenge-008/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..2dd3eccd25 --- /dev/null +++ b/challenge-008/archargelod/nim/ch_1.nim @@ -0,0 +1,13 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/math + +proc fivePerfectNumbers(): array[5, int] = + const Primes = [2, 3, 5, 7, 13] + for i, p in Primes: + result[i] = (2 ^ (p - 1)) * (2 ^ p - 1) + +when isMainModule: + import std/unittest + suite "Perfect numbers": + test "first 5 perfect numbers": + check fivePerfectNumbers() == [6, 28, 496, 8128, 33550336] diff --git a/challenge-008/archargelod/nim/ch_2.nim b/challenge-008/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..d96b378446 --- /dev/null +++ b/challenge-008/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 center(lines: varargs[string]): seq[string] = + let maxOffset = block: + var maxLen = 0 + for line in lines: + if line.len > maxLen: + maxLen = line.len + maxLen div 2 + + for line in lines: + result.add ' '.repeat(maxOffset - line.len div 2) & line + +when isMainModule: + import std/unittest + + const Example = ["This", "is", "a test of the", "center function"] + const Expected = [" This", " is", " a test of the", "center function"] + + suite "Centering strings": + test "Example 1": + check center(Example) == Expected diff --git a/challenge-009/archargelod/README b/challenge-009/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-009/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-009/archargelod/nim/ch_1.nim b/challenge-009/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..817d551fef --- /dev/null +++ b/challenge-009/archargelod/nim/ch_1.nim @@ -0,0 +1,19 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +proc distinctDigitsCount(number: int): int = + var digits: set[char] + for d in $number: + if d notin digits: + digits.incl d + digits.len + +proc findSquareNDistinctDigits*(digits: range[1 .. 10]): int = + var n = 1 + while result.distinctDigitsCount < digits: + result = n * n + inc n + +when isMainModule: + import std/unittest + suite "Square with 5 distinct digits": + test "12769 is the first square with 5 distinct digits": + check findSquareNDistinctDigits(5) == 12769 diff --git a/challenge-009/archargelod/nim/ch_2.nim b/challenge-009/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..6105f56f60 --- /dev/null +++ b/challenge-009/archargelod/nim/ch_2.nim @@ -0,0 +1,59 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[algorithm] + +type + IndexedItems[T] = seq[tuple[val: T, idx: int]] + TieStrategy = enum + Standard + Modified + Dense + +proc standardRanking(items: sink IndexedItems): seq[int] = + result = newSeq[int](items.len) + var currentRank = 1 + for i, (item, idx) in items: + if i > 0 and items[i - 1].val < item: + currentRank = i + 1 + result[idx] = currentRank + +proc modifiedRanking(items: sink IndexedItems): seq[int] = + result = newSeq[int](items.len) + var currentRank = items.len + for i in countDown(items.high, 0): + let (item, idx) = items[i] + if i < items.high and items[i + 1].val > item: + currentRank = i + 1 + result[idx] = currentRank + +proc denseRanking(items: sink IndexedItems): seq[int] = + result = newSeq[int](items.len) + var currentRank = 1 + for i, (item, idx) in items: + if i > 0 and items[i - 1].val < item: + inc currentRank + result[idx] = currentRank + +proc rank*[T](items: openArray[T], strategy: TieStrategy = Standard): seq[int] = + var indexedItems = newSeq[tuple[val: T, idx: int]](items.len) + for idx, val in items: + indexedItems[idx] = (val, idx) + + indexedItems.sort() + + case strategy + of Standard: + standardRanking(indexedItems) + of Modified: + modifiedRanking(indexedItems) + of Dense: + denseRanking(indexedItems) + +when isMainModule: + import std/unittest + suite "Standard/modified/dense ranking": + test "standard ranking": + check [0, 4, 4, 5].rank(Standard) == [1, 2, 2, 4] + test "modified ranking": + check [0, 4, 4, 5].rank(Modified) == [1, 3, 3, 4] + test "dense ranking": + check [0, 4, 4, 5].rank(Dense) == [1, 2, 2, 3] diff --git a/challenge-010/archargelod/README b/challenge-010/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-010/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-010/archargelod/nim/ch_1.nim b/challenge-010/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..ca4c236d12 --- /dev/null +++ b/challenge-010/archargelod/nim/ch_1.nim @@ -0,0 +1,66 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/tables + +type RomanNumeral = string + +const + validRomanDigits = "IVXLCDM" + RomanToDec = { + "M": 1000, + "CM": 900, + "D": 500, + "CD": 400, + "C": 100, + "XC": 90, + "L": 50, + "XL": 40, + "X": 10, + "IX": 9, + "V": 5, + "IV": 4, + "I": 1 + }.toOrderedTable + +proc toRoman*(number: 1 .. 3999): RomanNumeral = + var number: int = number + while number > 0: + for roman, dec in RomanToDec: + if number >= dec: + number -= dec + result.add roman + break + +proc toDec*(roman: RomanNumeral): int = + if roman.len < 1: + raise newException(ValueError, "Invalid roman numeral") + var prev = int.high + for romanDigit in roman: + if romanDigit notin validRomanDigits: + raise newException(ValueError, "Invalid roman numeral") + let cur = RomanToDec[$romanDigit] + if cur > prev: + result -= prev * 2 + result += cur + prev = cur + + if result notin 0 .. 3999: + raise newException(ValueError, "Invalid roman numeral") + +when isMainModule: + import std/unittest + + const + TestNumber = 246 + Expected = "CCXLVI" + + suite "Roman numeral encode/decode": + test "246 should be CCXLVI": + check TestNumber.toRoman == Expected + test "number encoded then decoded equals itself": + check TestNumber.toRoman.toDec == TestNumber + test "roman numerals with invalid digits are invalid": + expect ValueError: + discard "Hello".toDec + test "roman numerals outside of range 1..3999 are invalid": + expect ValueError: + discard "MMMMMMM".toDec diff --git a/challenge-010/archargelod/nim/ch_2.nim b/challenge-010/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..e06717f39c --- /dev/null +++ b/challenge-010/archargelod/nim/ch_2.nim @@ -0,0 +1,71 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off + +proc jaroSimilarity*(s1, s2: string): float = + if min(s1.len, s2.len) < 1: raise newException(ValueError, "strings can't be empty") + let margin = int max(s1.len, s2.len) div 2 - 1 + var + matches = (newSeq[bool](s1.len), newSeq[bool](s2.len)) + m: int + t: float + + # number of matches in order + for i, c in s1: + var left = max(s2.low, i - margin) + let right = max(s2.low, min(s2.high, i + margin)) + var pos = s2[left .. right].find(c) + if pos == -1: continue + + while left+pos < s2.high and matches[1][left+pos]: + left = left + pos + 1 # shift search start past the previous find + pos = s2[left .. right].find(c) + + if left + pos > s2.high: + pos = -1 + + matches[0][i] = true + matches[1][left + pos] = true + inc m + + if m == 0: return 0 + + # count transpositions + var mInd2 = 0 + for mInd1, matched in matches[0]: + if not matched: continue + while not matches[1][mInd2]: + inc mInd2 + if s1[mInd1] != s2[mInd2]: + t += 1 + inc mInd2 + t /= 2 + + 1/3 * (m/s1.len + m/s2.len + (m.float - t)/m.float) + +proc jaroWinklerSimilarity*(s1, s2: string, p = 0.1): float = + if min(s1.len, s2.len) < 1: raise newException(ValueError, "strings can't be empty") + if p < 0 or p > 0.25: + raiseAssert("P should not exceed 0.25, as similarity could become > 1") + + # common prefix + var l: int + for i, c in s1[0 .. min(s1.high, 3)]: + if i > s2.high or s2[i] != c: + break + l = i + 1 + + let simj = jaroSimilarity(s1, s2) + simj + l.float * p * (1 - simj) + +proc jaroWinklerDistance*(s1, s2: string, p = 0.1): float = + if min(s1.len, s2.len) < 1: raise newException(ValueError, "strings can't be empty") + 1 - jaroWinklerSimilarity(s1, s2, p) + +when isMainModule: + import std/[unittest] + + proc approxEqual(a, b, tolerance: float): bool = + return abs(a - b) <= tolerance + + suite "Jaro-Winkler string distance": + test "similarity of 'faremviel' and 'farmville' is around 0.88": + check approxEqual(jaroSimilarity("faremviel", "farmville"), 0.88, 0.01) diff --git a/challenge-011/archargelod/README b/challenge-011/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-011/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-011/archargelod/nim/ch_1.nim b/challenge-011/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..b7514dd648 --- /dev/null +++ b/challenge-011/archargelod/nim/ch_1.nim @@ -0,0 +1,24 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/math + +const + CelsiusFreezing = 0 + CelsiusBoiling = 100 + FahrenheitFreezing = 32 + FahrenheitBoiling = 212 + +proc toFahrenheit(t: int): int = + let slope = + (FahrenheitBoiling - FahrenheitFreezing) / (CelsiusBoiling - CelsiusFreezing) + int round(FahrenheitFreezing.float + slope * float(t - CelsiusFreezing)) + +proc equalPoint(): int = + while result.toFahrenheit() > result: + dec result + +when isMainModule: + import std/unittest + + suite "Equal point in Fahrenheit and Celsius": + test "-40 is the equal point": + check equalPoint() == -40 diff --git a/challenge-011/archargelod/nim/ch_2.nim b/challenge-011/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..6865bd40f5 --- /dev/null +++ b/challenge-011/archargelod/nim/ch_2.nim @@ -0,0 +1,25 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[sequtils] + +type Matrix = seq[seq[int]] + +proc identityMatrix*(size: Positive): Matrix = + result = newSeqWith[int](size, newSeq[int](size)) + for i in 0 ..< size: + result[i][i] = 1 + +when isMainModule: + import std/unittest + + suite "Identity matrix of given size": + test "2x2 matrix": + check identityMatrix(2) == [@[1, 0], @[0, 1]] + test "6x6 matrix": + check identityMatrix(6) == [ + @[1, 0, 0, 0, 0, 0], + @[0, 1, 0, 0, 0, 0], + @[0, 0, 1, 0, 0, 0], + @[0, 0, 0, 1, 0, 0], + @[0, 0, 0, 0, 1, 0], + @[0, 0, 0, 0, 0, 1] + ] diff --git a/challenge-012/archargelod/README b/challenge-012/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-012/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-012/archargelod/nim/ch_1.nim b/challenge-012/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..c64a70a11e --- /dev/null +++ b/challenge-012/archargelod/nim/ch_1.nim @@ -0,0 +1,33 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/math + +const Primes = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, + 83, 89, 97 +] + +proc isPrime(n: int): bool = + if n == 2 or n == 3: + return true + elif n mod 3 == 0 or n mod 2 == 0: + return false + + for i in 5 .. sqrt(n.float).int: + if n mod i == 0: + return false + true + +proc smallestNonPrimeEuclidNumber(): int = + var product = 1 + for i, prime in Primes: + product = product * prime + let euclidNumber = product + 1 + if not euclidNumber.isPrime: + return euclidNumber + +when isMainModule: + import std/unittest + + suite "Smallest non-prime Euclid number": + test "smalles nonprime euclid number is 30031": + check smallestNonPrimeEuclidNumber() == 30031 diff --git a/challenge-012/archargelod/nim/ch_2.nim b/challenge-012/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..ed6b057a67 --- /dev/null +++ b/challenge-012/archargelod/nim/ch_2.nim @@ -0,0 +1,43 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[parseutils, strformat, strutils] + +proc commonPath(paths: openarray[string], sep = '/'): string = + var stack: seq[string] + for pathInd, path in paths: + if path[0] != sep: + raise newException(ValueError, &"paths should start with '{sep}'") + + var depth = 0 + var index = 1 + while index <= path.high: + let dirLength = path.skipUntil({sep}, index) + + if dirLength < 1: # treat multiple separators as one (how it works on linux) + inc index + continue + + let dirName = path[index ..< index + dirLength] + + if pathInd == 0: + stack.add dirName + elif depth > stack.high or stack[depth] != dirName: + stack.setLen(depth) + break + elif depth == stack.high: + break + + inc depth + index += dirLength + 1 + + sep & stack.join($sep) + +when isMainModule: + import std/unittest + + const + TestPaths = ["/a/b/c/d", "/a/b/cd", "/a/b/cc", "/a/b/c/d/e"] + Expected = "/a/b" + + suite "Common directory": + test "Example 1": + check commonPath(TestPaths) == Expected diff --git a/challenge-013/archargelod/README b/challenge-013/archargelod/README new file mode 100644 index 0000000000..6cd57e1074 --- /dev/null +++ b/challenge-013/archargelod/README @@ -0,0 +1 @@ +Solution by archargelod diff --git a/challenge-013/archargelod/nim/ch_1.nim b/challenge-013/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..2a1c49068b --- /dev/null +++ b/challenge-013/archargelod/nim/ch_1.nim @@ -0,0 +1,22 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[times, strformat, math] + +proc lastWeekdayOfEveryMonth(weekDay: WeekDay, year: int): seq[string] = + for month in Month: + let + lastMonthDay = getDaysInMonth(month, year) + lastWeekDay = getDayOfWeek(lastMonthDay, month, year).ord + lastFriday = lastMonthDay - euclmod(lastWeekDay - weekDay.ord, 7) + + result.add &"{year:04}/{month.ord:02}/{lastFriday:02}" + +when isMainModule: + import std/unittest + + suite "Last Fridays of every month": + test "last Fridays of 2019": + check lastWeekdayOfEveryMonth(dFri, 2019) == [ + "2019/01/25", "2019/02/22", "2019/03/29", "2019/04/26", "2019/05/31", + "2019/06/28", "2019/07/26", "2019/08/30", "2019/09/27", "2019/10/25", + "2019/11/29", "2019/12/27" + ] diff --git a/challenge-013/archargelod/nim/ch_2.nim b/challenge-013/archargelod/nim/ch_2.nim new file mode 100755 index 0000000000..1797614c41 --- /dev/null +++ b/challenge-013/archargelod/nim/ch_2.nim @@ -0,0 +1,57 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/tables + +type MethodKind = enum + M + F + +proc m(n: Natural, memo: var Table[(MethodKind, int), int]): int + +proc f(n: Natural, memo: var Table[(MethodKind, int), int]): int = + if (F, n) in memo: + return memo[(F, n)] + + result = + if n == 0: + 1 + else: + n - m(f(n - 1, memo), memo) + + memo[(F, n)] = result + +proc m(n: Natural, memo: var Table[(MethodKind, int), int]): int = + if (M, n) in memo: + return memo[(M, n)] + + result = + if n == 0: + 0 + else: + n - f(m(n - 1, memo), memo) + + memo[(M, n)] = result + +when isMainModule: + import std/[sugar, unittest] + + const + Count = 20 + ExpectedM = [0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12] + ExpectedF = [1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, 11, 12] + + suite "Mutually Recursive methods": + var memo: Table[(MethodKind, int), int] + + test "First 20 Terms of F()": + check: + collect( + for i in 0 ..< Count: + f(i, memo) + ) == ExpectedF + + test "First 20 Terms of M()": + check: + collect( + for i in 0 ..< Count: + m(i, memo) + ) == ExpectedM diff --git a/challenge-257/archargelod/nim/ch_1.nim b/challenge-257/archargelod/nim/ch_1.nim new file mode 100755 index 0000000000..c1635ff5ec --- /dev/null +++ b/challenge-257/archargelod/nim/ch_1.nim @@ -0,0 +1,38 @@ +#!/usr/bin/env -S nim r -d:release --verbosity:0 --hints:off +import std/[sugar, algorithm] + +proc mapToSmallerValuesCount*(numbers: sink seq[int]): seq[int] = + ## ~10x faster than naive method + var indexed = collect( + for i, n in numbers: + (i, n) + ) + indexed.sort((t1, t2) => cmp(t1[1], t2[1])) + + result = numbers + + var prev: tuple[val, index: int] + for curIndex, (origIndex, curVal) in indexed: + result[origIndex] = + if curVal == prev.val: + prev.index + else: + prev = (curVal, curIndex) + curIndex + +when isMainModule: + import std/unittest + + const + Test = [@[5, 2, 1, 6], @[1, 2, 0, 3], @[0, 1], @[9, 4, 9, 2]] |
