Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/exercises.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,9 @@ jobs:

- name: Run `check_exercises`
run: _test/check_exercises

- name: Compile `check_stubs.nim`
run: nim c --styleCheck:error _test/check_stubs.nim

- name: Run `check_stubs`
run: _test/check_stubs
55 changes: 55 additions & 0 deletions _test/check_stubs.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import std/[os, osproc, strformat, strutils]

iterator walkExerciseDirs: string =
const repoRootDir = currentSourcePath().parentDir().parentDir()
for exerciseKind in ["concept", "practice"]:
for exerciseDir in walkDirs(repoRootDir / "exercises" / exerciseKind / "*"):
yield exerciseDir

proc checkStubs: seq[string] =
## Compiles and runs the test file for every exercise, using the user-facing
## solution stub.
##
## Returns the exercise slugs for which the corresponding test file either:
##
## - compiles with an error
##
## - runs without an error (the solution stub is supposed to fail the tests)
result = @[]
stderr.writeLine "Checking stubs..."
for exerciseDir in walkExerciseDirs():
let slug = exerciseDir.lastPathPart()
let testPath = exerciseDir / &"test_{slug.replace('-', '_')}.nim"
stderr.writeLine &"{slug}"
const nimOptions = "--hints:off --usenimcache --filenames:canonical " &
"--spellSuggest:0 --styleCheck:error"
let (outpCompile, errCompile) = execCmdEx(&"nim c {nimOptions} {testPath}")
if errCompile == 0:
let (outpRun, errRun) = execCmdEx(&"nim r --hints:off {testPath}")
if errRun == 0:
stderr.write outpRun
stderr.writeLine &"Error: the {slug} stub passed the tests\n"
result.add slug
else:
stderr.writeLine outpCompile
result.add slug

proc main =
let errorSlugs = checkStubs()
if errorSlugs.len > 0:
let msg = fmt"""

Error: there were {errorSlugs.len} exercises with a problematic stub:
{errorSlugs.join(", ")}""".unindent()
echo msg
quit 1
else:
const msg = """

Success. Every exercise has a test file and stub that:
- compiles without error
- runs with an error (we want the stub to fail the tests)""".unindent()
echo msg

when isMainModule:
main()
14 changes: 14 additions & 0 deletions exercises/concept/lasagna/lasagna.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
let expectedMinutesInOven* = 5

proc remainingMinutesInOven*(actualMinutesInOven: int): int =
## Returns the number of minutes that the lasagna still needs to remain in the
## oven to be properly prepared.
discard

proc preparationTimeInMinutes*(numberOfLayers: int): int =
## Returns the total preparation time for a given number of layers.
discard

proc totalTimeInMinutes*(numberOfLayers, actualMinutesInOven: int): int =
## Returns the total time required to prepare the lasagna.
discard
2 changes: 2 additions & 0 deletions exercises/practice/acronym/acronym.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc abbreviate*(s: string): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/all-your-base/all_your_base.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc convert*(digits: openArray[int], fromBase: int, toBase: int): seq[int] =
discard
9 changes: 9 additions & 0 deletions exercises/practice/allergies/allergies.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type
Allergen* = enum
Eggs, Peanuts, Shellfish, Strawberries, Tomatoes, Chocolate, Pollen, Cats

proc isAllergicTo*(score: int, allergen: Allergen): bool =
discard

proc allergies*(score: int): set[Allergen] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/anagram/anagram.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc detectAnagrams*(word: string, candidates: openArray[string]): seq[string] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/armstrong-numbers/armstrong_numbers.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc isArmstrongNumber*(n: int): bool =
discard
5 changes: 5 additions & 0 deletions exercises/practice/atbash-cipher/atbash_cipher.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
proc encode*(s: string): string =
discard

proc decode*(s: string): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/binary/binary.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc binary*(s: string): int =
discard
2 changes: 2 additions & 0 deletions exercises/practice/bob/bob.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc hey*(s: string): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/collatz-conjecture/collatz_conjecture.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc steps*(n: int): int =
discard
2 changes: 2 additions & 0 deletions exercises/practice/crypto-square/crypto_square.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc encrypt*(s: string): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/darts/darts.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc score*(x, y: float): int =
discard
2 changes: 2 additions & 0 deletions exercises/practice/diamond/diamond.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc diamond*(c: char): string =
discard
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
proc squareOfSum*(n: int): int =
discard

proc sumOfSquares*(n: int): int =
discard

proc difference*(n: int): int =
discard
8 changes: 8 additions & 0 deletions exercises/practice/diffie-hellman/diffie_hellman.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
proc privateKey*(p: int): int =
discard

proc publicKey*(p, g, a: int): int =
discard

proc secret*(p, bPub, a: int): int =
discard
6 changes: 6 additions & 0 deletions exercises/practice/dnd-character/dnd_character.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
type
Character* = object
strength*: int
dexterity*: int
constitution*: int
intelligence*: int
wisdom*: int
charisma*: int
hitpoints*: int

proc ability*: int =
discard
Expand Down
4 changes: 4 additions & 0 deletions exercises/practice/etl/etl.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import std/tables

proc transform*(t: Table[int, seq[char]]): Table[char, int] =
discard
4 changes: 4 additions & 0 deletions exercises/practice/gigasecond/gigasecond.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import std/times

proc addGigasecond*(dt: DateTime): DateTime =
discard
22 changes: 22 additions & 0 deletions exercises/practice/grade-school/grade_school.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
type
Student* = object
name*: string
grade*: int

School* = object
students*: seq[Student]

proc roster*(school: School): seq[string] =
## Returns the names of every student in the `school`, sorted by grade then name.
discard

proc addStudent*(school: var School, name: string, grade: int) =
## Adds a student with `name` and `grade` to the `school`.
##
## Raises a `ValueError` if `school` already contains a student named `name`.
discard

proc grade*(school: School, grade: int): seq[string] =
## Returns the names of the students in the given `school` and `grade`, in
## alphabetical order.
discard
5 changes: 5 additions & 0 deletions exercises/practice/grains/grains.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
proc onSquare*(n: int): uint64 =
discard

proc total*: uint64 =
discard
2 changes: 2 additions & 0 deletions exercises/practice/hamming/hamming.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc distance*(a, b: string): int =
discard
8 changes: 8 additions & 0 deletions exercises/practice/high-scores/high_scores.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
proc latest*(scores: openArray[int]): int =
discard

proc personalBest*(scores: openArray[int]): int =
discard

proc personalTopThree*(scores: openArray[int]): seq[int] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/isbn-verifier/isbn_verifier.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc isValid*(s: string): bool =
discard
2 changes: 2 additions & 0 deletions exercises/practice/isogram/isogram.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc isIsogram*(s: string): bool =
discard
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type
Plant* = enum
Clover, Grass, Radishes, Violets

proc plants*(garden: string, student: string): seq[Plant] =
discard
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc largestProduct*(s: string, span: int): int =
discard
2 changes: 2 additions & 0 deletions exercises/practice/leap/leap.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc isLeapYear*(year: int): bool =
discard
2 changes: 2 additions & 0 deletions exercises/practice/luhn/luhn.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc isValid*(s: string): bool =
discard
2 changes: 2 additions & 0 deletions exercises/practice/matching-brackets/matching_brackets.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc isPaired*(s: string): bool =
discard
5 changes: 5 additions & 0 deletions exercises/practice/matrix/matrix.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
proc row*(s: string, n: int): seq[int] =
discard

proc column*(s: string, n: int): seq[int] =
discard
8 changes: 8 additions & 0 deletions exercises/practice/meetup/meetup.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import std/times

type
Schedule* = enum
Teenth, First, Second, Third, Fourth, Last

proc meetup*(year: int, month: int, schedule: Schedule, day: WeekDay): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/nth-prime/nth_prime.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc prime*(n: int): int =
discard
4 changes: 4 additions & 0 deletions exercises/practice/nucleotide-count/nucleotide_count.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import std/tables

proc countDna*(s: string): CountTable[char] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/pangram/pangram.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc isPangram*(s: string): bool =
discard
2 changes: 2 additions & 0 deletions exercises/practice/pascals-triangle/pascals_triangle.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc pascal*(n: int): seq[seq[int]] =
discard
6 changes: 6 additions & 0 deletions exercises/practice/perfect-numbers/perfect_numbers.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type
Classification* = enum
Perfect, Deficient, Abundant

proc classify*(n: int): Classification =
discard
2 changes: 2 additions & 0 deletions exercises/practice/phone-number/phone_number.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc clean*(s: string): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/prime-factors/prime_factors.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc primeFactors*(n: int64): seq[int] =
discard
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc translate*(s: string): seq[string] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/proverb/proverb.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc recite*(words: openArray[string]): string =
discard
13 changes: 13 additions & 0 deletions exercises/practice/queen-attack/queen_attack.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
type
Queen* = object
row*: int
col*: int

proc initQueen*(row, col: int): Queen =
discard

proc canAttack*(white, black: Queen): bool =
discard

proc board*(white, black: Queen): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/raindrops/raindrops.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc convert*(n: int): string =
discard
6 changes: 6 additions & 0 deletions exercises/practice/resistor-color-duo/resistor_color_duo.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type
ResistorColor* = enum
Black, Brown, Red, Orange, Yellow, Green, Blue, Violet, Grey, White

proc value*(colors: openArray[ResistorColor]): int =
discard
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type
ResistorColor* = enum
Black, Brown, Red, Orange, Yellow, Green, Blue, Violet, Grey, White

proc label*(r: array[3, ResistorColor]): tuple[value: int, unit: string] =
discard
9 changes: 9 additions & 0 deletions exercises/practice/resistor-color/resistor_color.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type
ResistorColor* = enum
Black, Brown, Red, Orange, Yellow, Green, Blue, Violet, Grey, White

proc colorCode*(color: ResistorColor): int =
discard

proc colors*: array[0..ResistorColor.high.ord, ResistorColor] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/reverse-string/reverse_string.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc reverse*(s: string): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/rna-transcription/rna_transcription.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc toRna*(s: string): string =
discard
10 changes: 10 additions & 0 deletions exercises/practice/robot-name/robot_name.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type
Name* = array[5, char]
Robot* = object
name*: Name

proc makeRobot*: Robot =
discard

proc reset*(r: var Robot) =
discard
2 changes: 2 additions & 0 deletions exercises/practice/roman-numerals/roman_numerals.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc roman*(n: int): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/rotational-cipher/rotational_cipher.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc rotate*(s: string, n: int): string =
discard
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
proc encode*(s: string): string =
discard

proc decode*(s: string): string =
discard
2 changes: 2 additions & 0 deletions exercises/practice/saddle-points/saddle_points.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc saddlePoints*(matrix: seq[seq[int]]): seq[tuple[r, c: int]] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/say/say.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc say*(n: int64): string =
discard
6 changes: 6 additions & 0 deletions exercises/practice/scale-generator/scale_generator.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import std/strutils

const chromaticIntervals = "m".repeat(11)

proc scale*(tonic: string, intervals = chromaticIntervals): seq[string] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/scrabble-score/scrabble_score.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc score*(word: string): int =
discard
2 changes: 2 additions & 0 deletions exercises/practice/secret-handshake/secret_handshake.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc commands*(n: int): seq[string] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/series/series.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc slices*(s: string, n: int): seq[string] =
discard
2 changes: 2 additions & 0 deletions exercises/practice/sieve/sieve.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc primes*(limit: int): seq[int] =
discard
6 changes: 6 additions & 0 deletions exercises/practice/space-age/space_age.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type
Planet* = enum
Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune

proc age*(planet: Planet, seconds: int64): float =
discard
2 changes: 2 additions & 0 deletions exercises/practice/spiral-matrix/spiral_matrix.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc spiral*(n: static int): array[n, array[n, int]] =
discard
6 changes: 6 additions & 0 deletions exercises/practice/sublist/sublist.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type
Comparison* = enum
Unequal, Sublist, Superlist, Equal

proc sublist*(a, b: openArray[int]): Comparison =
discard
2 changes: 2 additions & 0 deletions exercises/practice/sum-of-multiples/sum_of_multiples.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc sum*(limit: int, factors: openArray[int]): int =
discard
Loading