Repository: exercism/kotlin Branch: main Commit: a7d115e1df85 Files: 1488 Total size: 2.1 MB Directory structure: gitextract_p8afkg7r/ ├── .appends/ │ └── .github/ │ └── labels.yml ├── .github/ │ ├── CODEOWNERS │ ├── dependabot.yml │ ├── labels.yml │ └── workflows/ │ ├── configlet.yml │ ├── no-important-files-changed.yml │ ├── pause-community-contributions.yml │ ├── ping-cross-track-maintainers-team.yml │ ├── run-configlet-sync.yml │ ├── sync-labels.yml │ └── test.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── _template/ │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle.kts │ └── src/ │ ├── example/ │ │ └── kotlin/ │ │ └── .keep │ ├── main/ │ │ └── kotlin/ │ │ └── .keep │ └── test/ │ └── kotlin/ │ └── .keep ├── bin/ │ ├── README.md │ ├── build-jq.sh │ ├── fetch-configlet │ ├── journey-test.sh │ ├── run-journey-test-from-ci.sh │ └── unit-tests.sh ├── concepts/ │ ├── basics/ │ │ ├── .meta/ │ │ │ └── config.json │ │ ├── about.md │ │ ├── introduction.md │ │ └── links.json │ ├── bitwise-operations/ │ │ ├── .meta/ │ │ │ └── config.json │ │ ├── about.md │ │ ├── introduction.md │ │ └── links.json │ ├── booleans/ │ │ ├── .meta/ │ │ │ └── config.json │ │ ├── about.md │ │ ├── introduction.md │ │ └── links.json │ ├── chars/ │ │ ├── .meta/ │ │ │ └── config.json │ │ ├── about.md │ │ ├── introduction.md │ │ └── links.json │ ├── conditionals/ │ │ ├── .meta/ │ │ │ └── config.json │ │ ├── about.md │ │ ├── introduction.md │ │ └── links.json │ ├── nullability/ │ │ ├── .meta/ │ │ │ └── config.json │ │ ├── about.md │ │ ├── introduction.md │ │ └── links.json │ └── strings/ │ ├── .meta/ │ │ └── config.json │ ├── about.md │ ├── introduction.md │ └── links.json ├── config.json ├── docs/ │ ├── ABOUT.md │ ├── INSTALLATION.md │ ├── LEARNING.md │ ├── RESOURCES.md │ ├── SNIPPET.txt │ ├── TESTS.md │ └── config.json ├── exercises/ │ ├── build.gradle.kts │ ├── concept/ │ │ ├── annalyns-infiltration/ │ │ │ ├── .docs/ │ │ │ │ ├── hints.md │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── design.md │ │ │ │ └── src/ │ │ │ │ └── reference/ │ │ │ │ └── kotlin/ │ │ │ │ └── AnnalynsInfiltration.kt │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── AnnalynsInfiltration.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── AnnalynsInfiltrationTest.kt │ │ ├── log-levels/ │ │ │ ├── .docs/ │ │ │ │ ├── hints.md │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ └── src/ │ │ │ │ └── reference/ │ │ │ │ └── kotlin/ │ │ │ │ └── LogLevels.kt │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── LogLevels.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── LogLevelsTest.kt │ │ └── lucians-luscious-lasagna/ │ │ ├── .docs/ │ │ │ ├── hints.md │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta/ │ │ │ ├── config.json │ │ │ ├── design.md │ │ │ └── src/ │ │ │ └── reference/ │ │ │ └── kotlin/ │ │ │ └── LuciansLusciousLasagna.kt │ │ ├── build.gradle.kts │ │ ├── gradle/ │ │ │ └── wrapper/ │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── settings.gradle.kts │ │ └── src/ │ │ ├── main/ │ │ │ └── kotlin/ │ │ │ └── LuciansLusciousLasagna.kt │ │ └── test/ │ │ └── kotlin/ │ │ └── LuciansLusciousLasagnaTests.kt │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ ├── practice/ │ │ ├── accumulate/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ └── src/ │ │ │ │ └── reference/ │ │ │ │ └── kotlin/ │ │ │ │ └── Accumulate.kt │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Accumulate.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── AccumulateTest.kt │ │ ├── acronym/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Acronym.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Acronym.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── AcronymTest.kt │ │ ├── affine-cipher/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── AffineCipher.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── AffineCipher.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── AffineCipherTest.kt │ │ ├── all-your-base/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── BaseConverter.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── BaseConverter.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BaseConverterTest.kt │ │ ├── allergies/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── Allergen.kt │ │ │ │ │ └── Allergies.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ ├── Allergen.kt │ │ │ │ └── Allergies.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── AllergiesTest.kt │ │ ├── anagram/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.append.md │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Anagram.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Anagram.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── AnagramTest.kt │ │ ├── armstrong-numbers/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── ArmstrongNumber.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── ArmstrongNumber.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ArmstrongNumberTest.kt │ │ ├── atbash-cipher/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Atbash.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Atbash.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── AtbashTest.kt │ │ ├── bank-account/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ └── src/ │ │ │ │ └── reference/ │ │ │ │ └── kotlin/ │ │ │ │ └── BankAccount.kt │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── BankAccount.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BankAccountTest.kt │ │ ├── beer-song/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── BeerSong.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── BeerSong.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BeerSongTest.kt │ │ ├── binary/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Binary.kt │ │ │ │ └── tests.toml │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Binary.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BinaryTest.kt │ │ ├── binary-search/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── BinarySearch.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── BinarySearch.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BinarySearchTest.kt │ │ ├── binary-search-tree/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── BinarySearchTree.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── BinarySearchTree.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BinarySearchTreeTest.kt │ │ ├── bob/ │ │ │ ├── .approaches/ │ │ │ │ ├── answer-list/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ ├── config.json │ │ │ │ ├── if-expressions/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ ├── introduction.md │ │ │ │ └── when-expression/ │ │ │ │ ├── content.md │ │ │ │ └── snippet.txt │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Bob.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Bob.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BobTest.kt │ │ ├── bottle-song/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── BottleSong.kt │ │ │ │ └── tests.toml │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── BottleSong.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BottleSongTest.kt │ │ ├── bowling/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── BowlingGame.kt │ │ │ │ │ └── Frame.kt │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── BowlingGame.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BowlingGameTest.kt │ │ ├── change/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── ChangeCalculator.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── ChangeCalculator.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ChangeCalculatorTest.kt │ │ ├── circular-buffer/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── CircularBuffer.kt │ │ │ │ └── tests.toml │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── CircularBuffer.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── CircularBufferTest.kt │ │ ├── clock/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Clock.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Clock.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ ├── ClockAddTest.kt │ │ │ ├── ClockCreationTest.kt │ │ │ ├── ClockEqualTest.kt │ │ │ └── ClockSubtractTest.kt │ │ ├── collatz-conjecture/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── CollatzCalculator.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── CollatzCalculator.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── CollatzCalculatorTest.kt │ │ ├── complex-numbers/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── ComplexNumber.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── ComplexNumber.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ComplexNumberTest.kt │ │ ├── crypto-square/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── CryptoSquare.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── CryptoSquare.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── CryptoSquareTest.kt │ │ ├── custom-set/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── CustomSet.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── CustomSet.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── CustomSetTest.kt │ │ ├── darts/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── hypot-for-radius/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── introduction.md │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Darts.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Darts.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── DartsTest.kt │ │ ├── diamond/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── DiamondPrinter.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── DiamondPrinter.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── DiamondPrinterTest.kt │ │ ├── difference-of-squares/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── formula/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── introduction.md │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── DifferenceOfSquares.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── DifferenceOfSquares.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── SquaresTest.kt │ │ ├── diffie-hellman/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── DiffieHellman.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── DiffieHellman.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── DiffieHellmanTest.kt │ │ ├── dnd-character/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── DndCharacter.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── DndCharacter.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── DndCharacterTest.kt │ │ ├── dominoes/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Dominoes.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Dominoes.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── DominoesTest.kt │ │ ├── eliuds-eggs/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── EliudsEggs.kt │ │ │ │ └── tests.toml │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── EliudsEggs.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── EliudsEggsTest.kt │ │ ├── etl/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── ETL.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── ETL.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ETLTest.kt │ │ ├── flatten-array/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Flattener.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Flattener.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── FlattenerTest.kt │ │ ├── flower-field/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── FlowerField.kt │ │ │ │ └── tests.toml │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── FlowerField.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── FlowerFieldTest.kt │ │ ├── forth/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Forth.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Forth.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ForthTest.kt │ │ ├── gigasecond/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── introduction.md │ │ │ │ └── secondary-constructor-atstartofday/ │ │ │ │ ├── content.md │ │ │ │ └── snippet.txt │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Gigasecond.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Gigasecond.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── GigasecondTest.kt │ │ ├── grade-school/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── GradeSchool.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── GradeSchool.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── SchoolTest.kt │ │ ├── grains/ │ │ │ ├── .approaches/ │ │ │ │ ├── bit-shifting/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ ├── config.json │ │ │ │ └── introduction.md │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Grains.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Grains.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── BoardTest.kt │ │ ├── hamming/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── introduction.md │ │ │ │ └── zip-count/ │ │ │ │ ├── content.md │ │ │ │ └── snippet.txt │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Hamming.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Hamming.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── HammingTest.kt │ │ ├── hello-world/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.append.md │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── HelloWorld.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── TUTORIAL.md │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── HelloWorld.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── HelloWorldTest.kt │ │ ├── hexadecimal/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ └── src/ │ │ │ │ └── reference/ │ │ │ │ └── kotlin/ │ │ │ │ └── Hexadecimal.kt │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Hexadecimal.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── HexadecimalTest.kt │ │ ├── isbn-verifier/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── fold-when-let/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── introduction.md │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── IsbnVerifier.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── IsbnVerifier.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── IsbnVerifierTest.kt │ │ ├── isogram/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Isogram.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Isogram.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── IsogramTest.kt │ │ ├── kindergarten-garden/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── KindergartenGarden.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── KindergartenGarden.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── KindergartenGardenTest.kt │ │ ├── knapsack/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Knapsack.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Knapsack.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── KnapsackTest.kt │ │ ├── largest-series-product/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── LargestSeriesProduct.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── LargestSeriesProduct.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── SeriesTest.kt │ │ ├── leap/ │ │ │ ├── .approaches/ │ │ │ │ ├── boolean-chain/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ ├── built-in-method/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ ├── config.json │ │ │ │ ├── introduction.md │ │ │ │ ├── plusdays/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── ternary-expression/ │ │ │ │ ├── content.md │ │ │ │ └── snippet.txt │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Leap.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Leap.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── LeapTest.kt │ │ ├── linked-list/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ └── src/ │ │ │ │ └── reference/ │ │ │ │ └── kotlin/ │ │ │ │ └── LinkedList.kt │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── LinkedList.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── DequeTest.kt │ │ ├── list-ops/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.append.md │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── ListOps.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── ListOps.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ListExtensionsTest.kt │ │ ├── luhn/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Luhn.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Luhn.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── LuhnTest.kt │ │ ├── matching-brackets/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── MatchingBrackets.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── MatchingBrackets.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── MatchingBracketsTest.kt │ │ ├── matrix/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Matrix.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Matrix.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── MatrixTest.kt │ │ ├── meetup/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── Meetup.kt │ │ │ │ │ └── MeetupSchedule.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ ├── Meetup.kt │ │ │ │ └── MeetupSchedule.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── MeetupTest.kt │ │ ├── minesweeper/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Minesweeper.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Minesweeper.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── MinesweeperBoardTest.kt │ │ ├── nth-prime/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── NthPrime.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── NthPrime.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── PrimeTest.kt │ │ ├── nucleotide-count/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── groupby-plus/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── introduction.md │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Dna.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Dna.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── DnaTest.kt │ │ ├── pangram/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Pangram.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Pangram.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── PangramTest.kt │ │ ├── pascals-triangle/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── PascalsTriangle.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── PascalsTriangle.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── PascalsTriangleTest.kt │ │ ├── perfect-numbers/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── NaturalNumber.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── NaturalNumber.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── NaturalNumberTest.kt │ │ ├── phone-number/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── PhoneNumber.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── PhoneNumber.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── PhoneNumberTest.kt │ │ ├── pig-latin/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── hashset-lookup/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── introduction.md │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── PigLatin.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── PigLatin.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── PigLatinTest.kt │ │ ├── prime-factors/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── PrimeFactors.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── PrimeFactors.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── PrimeFactorCalculatorTest.kt │ │ ├── protein-translation/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── ProteinTranslation.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── ProteinTranslation.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ProteinTranslationTest.kt │ │ ├── rail-fence-cipher/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── RailFenceCipher.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── RailFenceCipher.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── RailFenceCipherTest.kt │ │ ├── raindrops/ │ │ │ ├── .approaches/ │ │ │ │ ├── buildstring/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ ├── config.json │ │ │ │ ├── fold-on-list/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── introduction.md │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Raindrops.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Raindrops.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── RaindropsTest.kt │ │ ├── react/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── React.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── React.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ReactTest.kt │ │ ├── resistor-color/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── ResistorColor.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── ResistorColor.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ResistorColorTest.kt │ │ ├── resistor-color-duo/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── Color.kt │ │ │ │ │ └── ResistorColorDuo.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ ├── Color.kt │ │ │ │ └── ResistorColorDuo.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ResistorColorDuoTest.kt │ │ ├── resistor-color-trio/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── Color.kt │ │ │ │ │ ├── ResistorColorTrio.kt │ │ │ │ │ └── Unit.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ ├── Color.kt │ │ │ │ ├── ResistorColorTrio.kt │ │ │ │ └── Unit.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ResistorColorTrioTest.kt │ │ ├── reverse-string/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── ReverseString.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── ReverseString.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ReverseStringTest.kt │ │ ├── rna-transcription/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── RnaTranscription.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── RnaTranscription.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── RnaTranscriptionTest.kt │ │ ├── robot-name/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ └── src/ │ │ │ │ └── reference/ │ │ │ │ └── kotlin/ │ │ │ │ └── RobotName.kt │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── RobotName.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── RobotTest.kt │ │ ├── robot-simulator/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── GridPosition.kt │ │ │ │ │ ├── Orientation.kt │ │ │ │ │ └── Robot.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ ├── GridPosition.kt │ │ │ │ ├── Orientation.kt │ │ │ │ └── Robot.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── RobotTest.kt │ │ ├── roman-numerals/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── fold-repeat/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── introduction.md │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── RomanNumerals.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── RomanNumerals.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── RomanNumeralsTest.kt │ │ ├── rotational-cipher/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── RotationalCipher.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── RotationalCipher.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── RotationalCipherTest.kt │ │ ├── run-length-encoding/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── RunLengthEncoding.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── RunLengthEncoding.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── RunLengthEncodingTest.kt │ │ ├── saddle-points/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── Matrix.kt │ │ │ │ │ └── MatrixCoordinate.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Matrix.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── MatrixTest.kt │ │ ├── say/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Say.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Say.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── NumberSpellerTest.kt │ │ ├── scale-generator/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Scale.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Scale.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ScaleTest.kt │ │ ├── scrabble-score/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── introduction.md │ │ │ │ ├── map/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── when/ │ │ │ │ ├── content.md │ │ │ │ └── snippet.txt │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── ScrabbleScore.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── ScrabbleScore.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── ScrabbleScoreTest.kt │ │ ├── secret-handshake/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── HandshakeCalculator.kt │ │ │ │ │ └── Signal.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ ├── HandshakeCalculator.kt │ │ │ │ └── Signal.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── HandshakeCalculatorTest.kt │ │ ├── series/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Series.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Series.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── SeriesTest.kt │ │ ├── sieve/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Sieve.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Sieve.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── SieveTest.kt │ │ ├── simple-cipher/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── SimpleCipher.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── SimpleCipher.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ ├── IncorrectKeyCipherTest.kt │ │ │ ├── RandomKeyCipherTest.kt │ │ │ ├── SimpleCipherTest.kt │ │ │ └── SubstitutionCipherTest.kt │ │ ├── space-age/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── SpaceAge.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── SpaceAge.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── SpaceAgeTest.kt │ │ ├── spiral-matrix/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── SpiralMatrix.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── SpiralMatrix.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── SpiralMatrixTest.kt │ │ ├── strain/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ └── src/ │ │ │ │ └── reference/ │ │ │ │ └── kotlin/ │ │ │ │ └── Strain.kt │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Strain.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── StrainTest.kt │ │ ├── sublist/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── Relationship.kt │ │ │ │ │ └── Sublist.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Sublist.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── SublistTest.kt │ │ ├── sum-of-multiples/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── SumOfMultiples.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── SumOfMultiples.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── SumOfMultiplesTest.kt │ │ ├── transpose/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Transpose.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Transpose.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── TransposeTest.kt │ │ ├── triangle/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Triangle.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Triangle.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── TriangleTest.kt │ │ ├── two-fer/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── TwoFer.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── TwoFer.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── TwoFerTest.kt │ │ ├── word-count/ │ │ │ ├── .approaches/ │ │ │ │ ├── config.json │ │ │ │ ├── findall-groupingby-eachcount/ │ │ │ │ │ ├── content.md │ │ │ │ │ └── snippet.txt │ │ │ │ └── introduction.md │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── WordCount.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── WordCount.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── WordCountTest.kt │ │ ├── wordy/ │ │ │ ├── .docs/ │ │ │ │ └── instructions.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ └── Wordy.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ └── Wordy.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── WordyTest.kt │ │ ├── yacht/ │ │ │ ├── .docs/ │ │ │ │ ├── instructions.md │ │ │ │ └── introduction.md │ │ │ ├── .meta/ │ │ │ │ ├── config.json │ │ │ │ ├── src/ │ │ │ │ │ └── reference/ │ │ │ │ │ └── kotlin/ │ │ │ │ │ ├── Yacht.kt │ │ │ │ │ └── YachtCategory.kt │ │ │ │ ├── tests.toml │ │ │ │ └── version │ │ │ ├── build.gradle.kts │ │ │ ├── gradle/ │ │ │ │ └── wrapper/ │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ │ ├── gradlew │ │ │ ├── gradlew.bat │ │ │ ├── settings.gradle.kts │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── kotlin/ │ │ │ │ ├── Yacht.kt │ │ │ │ └── YachtCategory.kt │ │ │ └── test/ │ │ │ └── kotlin/ │ │ │ └── YachtTest.kt │ │ └── zebra-puzzle/ │ │ ├── .docs/ │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta/ │ │ │ ├── config.json │ │ │ ├── src/ │ │ │ │ └── reference/ │ │ │ │ └── kotlin/ │ │ │ │ ├── HeapsPermutation.kt │ │ │ │ └── ZebraPuzzle.kt │ │ │ ├── tests.toml │ │ │ └── version │ │ ├── build.gradle.kts │ │ ├── gradle/ │ │ │ └── wrapper/ │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── settings.gradle.kts │ │ └── src/ │ │ ├── main/ │ │ │ └── kotlin/ │ │ │ └── ZebraPuzzle.kt │ │ └── test/ │ │ └── kotlin/ │ │ └── ZebraPuzzleTest.kt │ ├── settings.gradle.kts │ └── shared/ │ └── .docs/ │ ├── help.md │ └── tests.md ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── reference/ │ └── implementing-a-concept-exercise.md └── scripts/ ├── canonical_data_check.sh ├── fix_exercises_symlinks.sh ├── updateGradleFilesFromTemplate.kts └── updateTemplateBuildFile.kts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .appends/.github/labels.yml ================================================ # ----------------------------------------------------------------------------------------- # # These are the repository-specific labels that augment the Exercise-wide labels defined in # # https://github.com/exercism/org-wide-files/blob/main/global-files/.github/labels.yml. # # ----------------------------------------------------------------------------------------- # - name: "good first issue" description: "" color: "fafafa" - name: "help wanted" description: "" color: "Ff7f00" - name: "issue: in progress" description: "Issue that is already occupied by somebody (usually by assigned person)." color: "7987f2" - name: "issue: meta" description: "Meta-discussions." color: "d4c5f9" - name: "issue: new exercise" description: "Request to add new exercise." color: "ff9682" - name: "issue: ready for dev" description: "Issue is ready for development." color: "97e87d" - name: "issue: requires investigation" description: "This issue requires further investigation from maintainers." color: "26b75e" - name: "issue: waiting response" description: "Issue marked with this label requires additional information from the author." color: "005b93" - name: "meta:v3" description: "Discussions related to exercism v3" color: "006b75" - name: "pr: dont merge" description: "Don't merge this PR for some reasons (e.g. tests are failing)." color: "ea3c99" - name: "pr: not ready" description: "" color: "ff0000" - name: "pr: rebase required" description: "PR marked with this label requires rebase on other branch (`master` by default)." color: "eeeeee" - name: "pr: review needed" description: "" color: "268902" ================================================ FILE: .github/CODEOWNERS ================================================ # Code owners .github/CODEOWNERS @exercism/maintainers-admin # Changes to `fetch-configlet` should be made in the `exercism/configlet` repo bin/fetch-configlet @exercism/maintainers-admin ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: # Keep dependencies for GitHub Actions up-to-date - package-ecosystem: 'github-actions' directory: '/' schedule: interval: 'monthly' ================================================ FILE: .github/labels.yml ================================================ # --------------------------------------------------------------- # # This is an auto-generated file - Do not manually edit this file # # --------------------------------------------------------------- # # This file is automatically generated by concatenating two files: # # 1. The Exercism-wide labels: defined in https://github.com/exercism/org-wide-files/blob/main/global-files/.github/labels.yml # 2. The repository-specific labels: defined in the `.appends/.github/labels.yml` file within this repository. # # If any of these two files change, a pull request is automatically created containing a re-generated version of this file. # Consequently, to change repository-specific labels you should update the `.appends/.github/labels.yml` file and _not_ this file. # # When the pull request has been merged, the GitHub labels will be automatically updated by the "Sync labels" workflow. # This typically takes 5-10 minutes. # --------------------------------------------------------------------- # # These are the Exercism-wide labels which are shared across all repos. # # --------------------------------------------------------------------- # # The following Exercism-wide labels are used to show "tasks" on the website, which will point users to things they can contribute to. # The `x:action/` labels describe what sort of work the contributor will be engaged in when working on the issue - name: "x:action/create" description: "Work on something from scratch" color: "ffffff" - name: "x:action/fix" description: "Fix an issue" color: "ffffff" - name: "x:action/improve" description: "Improve existing functionality/content" color: "ffffff" - name: "x:action/proofread" description: "Proofread text" color: "ffffff" - name: "x:action/sync" description: "Sync content with its latest version" color: "ffffff" # The `x:knowledge/` labels describe how much Exercism knowledge is required by the contributor - name: "x:knowledge/none" description: "No existing Exercism knowledge required" color: "ffffff" - name: "x:knowledge/elementary" description: "Little Exercism knowledge required" color: "ffffff" - name: "x:knowledge/intermediate" description: "Quite a bit of Exercism knowledge required" color: "ffffff" - name: "x:knowledge/advanced" description: "Comprehensive Exercism knowledge required" color: "ffffff" # The `x:module/` labels indicate what part of Exercism the contributor will be working on - name: "x:module/analyzer" description: "Work on Analyzers" color: "ffffff" - name: "x:module/concept" description: "Work on Concepts" color: "ffffff" - name: "x:module/concept-exercise" description: "Work on Concept Exercises" color: "ffffff" - name: "x:module/generator" description: "Work on Exercise generators" color: "ffffff" - name: "x:module/practice-exercise" description: "Work on Practice Exercises" color: "ffffff" - name: "x:module/representer" description: "Work on Representers" color: "ffffff" - name: "x:module/test-runner" description: "Work on Test Runners" color: "ffffff" # The `x:rep/` labels describe the amount of reputation to award # # For more information on reputation and how these labels should be used, # check out https://exercism.org/docs/using/product/reputation - name: "x:rep/tiny" description: "Tiny amount of reputation" color: "ffffff" - name: "x:rep/small" description: "Small amount of reputation" color: "ffffff" - name: "x:rep/medium" description: "Medium amount of reputation" color: "ffffff" - name: "x:rep/large" description: "Large amount of reputation" color: "ffffff" - name: "x:rep/massive" description: "Massive amount of reputation" color: "ffffff" # The `x:size/` labels describe the expected amount of work for a contributor - name: "x:size/tiny" description: "Tiny amount of work" color: "ffffff" - name: "x:size/small" description: "Small amount of work" color: "ffffff" - name: "x:size/medium" description: "Medium amount of work" color: "ffffff" - name: "x:size/large" description: "Large amount of work" color: "ffffff" - name: "x:size/massive" description: "Massive amount of work" color: "ffffff" # The `x:status/` label indicates if there is already someone working on the issue - name: "x:status/claimed" description: "Someone is working on this issue" color: "ffffff" # The `x:type/` labels describe what type of work the contributor will be engaged in - name: "x:type/ci" description: "Work on Continuous Integration (e.g. GitHub Actions workflows)" color: "ffffff" - name: "x:type/coding" description: "Write code that is not student-facing content (e.g. test-runners, generators, but not exercises)" color: "ffffff" - name: "x:type/content" description: "Work on content (e.g. exercises, concepts)" color: "ffffff" - name: "x:type/docker" description: "Work on Dockerfiles" color: "ffffff" - name: "x:type/docs" description: "Work on Documentation" color: "ffffff" # This Exercism-wide label is added to all automatically created pull requests that help migrate/prepare a track for Exercism v3 - name: "v3-migration 🤖" description: "Preparing for Exercism v3" color: "e99695" # This Exercism-wide label can be used to bulk-close issues in preparation for pausing community contributions - name: "paused" description: "Work paused until further notice" color: "e4e669" # ----------------------------------------------------------------------------------------- # # These are the repository-specific labels that augment the Exercise-wide labels defined in # # https://github.com/exercism/org-wide-files/blob/main/global-files/.github/labels.yml. # # ----------------------------------------------------------------------------------------- # - name: "good first issue" description: "" color: "fafafa" - name: "help wanted" description: "" color: "Ff7f00" - name: "issue: in progress" description: "Issue that is already occupied by somebody (usually by assigned person)." color: "7987f2" - name: "issue: meta" description: "Meta-discussions." color: "d4c5f9" - name: "issue: new exercise" description: "Request to add new exercise." color: "ff9682" - name: "issue: ready for dev" description: "Issue is ready for development." color: "97e87d" - name: "issue: requires investigation" description: "This issue requires further investigation from maintainers." color: "26b75e" - name: "issue: waiting response" description: "Issue marked with this label requires additional information from the author." color: "005b93" - name: "meta:v3" description: "Discussions related to exercism v3" color: "006b75" - name: "pr: dont merge" description: "Don't merge this PR for some reasons (e.g. tests are failing)." color: "ea3c99" - name: "pr: not ready" description: "" color: "ff0000" - name: "pr: rebase required" description: "PR marked with this label requires rebase on other branch (`master` by default)." color: "eeeeee" - name: "pr: review needed" description: "" color: "268902" ================================================ FILE: .github/workflows/configlet.yml ================================================ name: Configlet on: pull_request: push: branches: - main workflow_dispatch: permissions: contents: read jobs: configlet: uses: exercism/github-actions/.github/workflows/configlet.yml@main ================================================ FILE: .github/workflows/no-important-files-changed.yml ================================================ name: No important files changed on: pull_request_target: types: [opened] branches: [main] paths: - "exercises/concept/**" - "exercises/practice/**" - "!exercises/*/*/.approaches/**" - "!exercises/*/*/.articles/**" - "!exercises/*/*/.docs/**" - "!exercises/*/*/.meta/**" permissions: pull-requests: write jobs: check: uses: exercism/github-actions/.github/workflows/check-no-important-files-changed.yml@main with: repository: ${{ github.event.pull_request.head.repo.owner.login }}/${{ github.event.pull_request.head.repo.name }} ref: ${{ github.head_ref }} ================================================ FILE: .github/workflows/pause-community-contributions.yml ================================================ name: Pause Community Contributions on: issues: types: - opened pull_request_target: types: - opened paths-ignore: - 'exercises/*/*/.approaches/**' - 'exercises/*/*/.articles/**' permissions: issues: write pull-requests: write jobs: pause: if: github.repository_owner == 'exercism' # Stops this job from running on forks uses: exercism/github-actions/.github/workflows/community-contributions.yml@main with: forum_category: kotlin secrets: github_membership_token: ${{ secrets.COMMUNITY_CONTRIBUTIONS_WORKFLOW_TOKEN }} ================================================ FILE: .github/workflows/ping-cross-track-maintainers-team.yml ================================================ name: Ping cross-track maintainers team on: pull_request_target: types: - opened permissions: pull-requests: write jobs: ping: if: github.repository_owner == 'exercism' # Stops this job from running on forks uses: exercism/github-actions/.github/workflows/ping-cross-track-maintainers-team.yml@main secrets: github_membership_token: ${{ secrets.COMMUNITY_CONTRIBUTIONS_WORKFLOW_TOKEN }} ================================================ FILE: .github/workflows/run-configlet-sync.yml ================================================ name: Run Configlet Sync on: workflow_dispatch: schedule: - cron: '0 0 15 * *' jobs: call-gha-workflow: uses: exercism/github-actions/.github/workflows/configlet-sync.yml@main ================================================ FILE: .github/workflows/sync-labels.yml ================================================ name: Tools on: push: branches: - main paths: - .github/labels.yml - .github/workflows/sync-labels.yml workflow_dispatch: schedule: - cron: 0 0 1 * * # First day of each month permissions: issues: write jobs: sync-labels: uses: exercism/github-actions/.github/workflows/labels.yml@main ================================================ FILE: .github/workflows/test.yml ================================================ name: Kotlin / Test on: push: branches: [main] pull_request: workflow_dispatch: jobs: ci: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Run tests for all exercises run: bin/journey-test.sh ================================================ FILE: .gitignore ================================================ *.swp .DS_Store bin/configlet bin/configlet.exe bin/jq* CHECKLIST build .gradle .idea *.iml out/ ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Code of Conduct ## Introduction Exercism is a platform centered around empathetic conversation. We have a low tolerance for communication that makes anyone feel unwelcome, unsupported, insulted or discriminated against. ## Seen or experienced something uncomfortable? If you see or experience abuse, harassment, discrimination, or feel unsafe or upset, please email [abuse@exercism.org](mailto:abuse@exercism.org?subject=%5BCoC%5D) and include \[CoC\] in the subject line. We will follow up with you as a priority. ## Enforcement We actively monitor for Code of Conduct (CoC) violations and take any reports of violations extremely seriously. We have banned contributors, mentors and users due to violations. After we receive a report of a CoC violation, we view that person's conversation history on Exercism and related communication channels and attempt to understand whether someone has deliberately broken the CoC, or accidentally crossed a line. We generally reach out to the person who has been reported to discuss any concerns we have and warn them that repeated violations will result in a ban. Sometimes we decide that no violation has occurred and that no action is required and sometimes we will also ban people on a first offense. We strive to be fair, but will err on the side of protecting the culture of our community. Exercism's leadership reserve the right to take whatever action they feel appropriate with regards to CoC violations. ## The simple version - Be empathetic - Be welcoming - Be kind - Be honest - Be supportive - Be polite ## The details Exercism should be a safe place for everybody regardless of - Gender, gender identity or gender expression - Sexual orientation - Disability - Physical appearance (including but not limited to body size) - Race - Age - Religion - Anything else you can think of As someone who is part of this community, you agree that: - We are collectively and individually committed to safety and inclusivity - We have zero tolerance for abuse, harassment, or discrimination - We respect people’s boundaries and identities - We refrain from using language that can be considered offensive or oppressive (systemically or otherwise), eg. sexist, racist, homophobic, transphobic, ableist, classist, etc. - this includes (but is not limited to) various slurs. - We avoid using offensive topics as a form of humor We actively work towards: - Being a safe community - Cultivating a network of support & encouragement for each other - Encouraging responsible and varied forms of expression We condemn: - Stalking, doxxing, or publishing private information - Violence, threats of violence or violent language - Anything that compromises people’s safety - Conduct or speech which might be considered sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory or offensive in nature - The use of unwelcome, suggestive, derogatory or inappropriate nicknames or terms - Disrespect towards others (jokes, innuendo, dismissive attitudes) and towards differences of opinion - Intimidation or harassment (online or in-person). Please read the [Citizen Code of Conduct](https://github.com/stumpsyn/policies/blob/master/citizen_code_of_conduct.md) for how we interpret harassment - Inappropriate attention or contact - Not understanding the differences between constructive criticism and disparagement These things are NOT OK. Be aware of how your actions affect others. If it makes someone uncomfortable, stop. If you say something that is found offensive, and you are called out on it, try to: - Listen without interruption - Believe what the person is saying & do not attempt to disqualify what they have to say - Ask for tips / help with avoiding making the offense in the future - Apologize and ask forgiveness ## History This policy was initially adopted from the Front-end London Slack community and has been modified since. A version history can be seen on [GitHub](https://github.com/exercism/website-copy/edit/main/pages/code_of_conduct.md). _This policy is a "living" document, and subject to refinement and expansion in the future. This policy applies to the Exercism website, the Exercism GitHub organization, any other Exercism-related communication channels (e.g. Discord, Forum, Twitter, email) and any other Exercism entity or event._ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021 Exercism Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Exercism Kotlin Track [![Build Status](https://travis-ci.org/exercism/kotlin.svg?branch=master)](https://travis-ci.org/exercism/kotlin) Source for Exercism Exercises in Kotlin. ## Contributing Guide For general information about how to contribute to Exercism, please refer to the [contributing guide](https://exercism.org/docs/building). ## Table of Contents * [Overview](#overview) * [Contributing With Minimal Setup](#contributing-with-minimal-setup) * [Getting Familiar With the Codebase](#getting-familiar-with-the-codebase) * [The `exercises` Module](#the-exercises-module) * [The Problem Submodules](#the-problem-submodules) * [Advanced: Complete Local Setup](#advanced-complete-local-setup) * [Tip: `gradle clean` before `exercism fetch`](#tip-gradle-clean-before-exercism-fetch) ## Overview This guide covers contributing to the Kotlin track. If you are new, this guide is for you. If, at any point, you're having any trouble, pop in the [Building Exercism](https://forum.exercism.org/c/exercism/building-exercism/125) category of the [Exercism forum](https://forum.exercism.org/) for help. ## Contributing With Minimal Setup First things first: by contributing to Exercism, you are making this learning tool that much better and improving our industry as a whole... thank you!!! To submit a fix for an existing exercise or port an exercise to Kotlin with the least amount of setup: 1. **Ensure you have the basic Java tooling installed:** JDK 1.8+, an editor and Gradle 2.x. (see [exercism.io: Installing Kotlin](https://exercism.org/docs/tracks/kotlin/installation)) - **Setup a branch on a fork of [exercism/kotlin](https://github.com/exercism/kotlin) on your computer.** Next steps: * "fork" a repository on GitHub; - install `git`; - "clone" a copy of your fork; - configure an "upstream remote" (in this case, `exercism/kotlin`); - create a branch to house your work - **Write the codes.** Do your work on that branch you just created. The [Getting Familiar With the Codebase](#getting-familiar-with-the-codebase) section, below, is an orientation. - **Commit, push and create a pull request.** Something like: ``` $ git add . $ git commit -m "(An intention-revealing commit message)" $ git push ``` It is advised you write meaningful commit messages. [Chris Beams wrote about "How to Write a Git Commit Message"](https://chris.beams.io/posts/git-commit/). - **Verify that your work passes all tests.** When you create a pull request (PR), GitHub triggers a build on Travis CI. Your PR will not be merged unless those tests pass. ## Getting Familiar With the Codebase There are two objectives to the design of this build: 1. when a problem is built from within the `exercism/kotlin` repo (i.e. when you, the contributor, are developing the exercise), the tests run against the reference solution; 2. when a problem is built outside the `exercism/kotlin` repo (when a participant is solving the exercise), the tests run against the "main" code. This repo is a multi-project gradle build. ### The `exercises` Module This is the top-level module, contained in the `exercises` directory. It is a container for the problem sub-modules. * its `build.gradle` points the "main" sourceset to the reference solution. * its `settings.gradle` names each of the subprojects, one for each problem in the set. ### The Problem Submodules The `exercises` subdirectory contains all of the problem submodules. Each problem/submodule is a subdirectory of the same name as its slug. * its `build.gradle.kts` names dependencies required to work that problem. Each problem/submodule has three source sets: * `src/test/kotlin/` — a test suite defining the edges of the problem * `.meta/src/reference/kotlin/` — a reference solution that passes all the tests * `src/main/kotlin/` — starter source files, if required/desired *(this directory usually only has a `.keep` file in it)*. To run the tests for a specific exercise, run the `test` Gradle task from the exercises directory. For example: ```bash cd exercises https://github.com/exercism/v3/blob/main/gradlew bob:test ``` Steps for modifying an exercise: 1. Change the test(s). 2. Watch the changes fail. 3. Update the reference solution to make the test(s) pass. ---- ## Advanced: Complete Local Setup If you are going to make significant contribution(s) to the track, you might find it handy to have a complete local install of exercism on your computer. This way, you can run the full suite of tests without having to create/update a PR. The easiest way to achieve this is simply use the `bin/journey-test.sh` script. However, you may want to perform other tests, depending on what you are doing. You can do so by duplicating the setup performed by the `bin/journey-test.sh` script. ### Tip: `gradle clean` before `exercism fetch` If you `exercism fetch` after doing a build, the CLI will fail with the following error message: ``` $ exercism fetch kotlin bob 2015/09/06 15:03:21 an internal server error was received. Please file a bug report with the contents of 'exercism debug' at: https://github.com/exercism/exercism.io/issues ``` and if you review the logs of your x-api, you'll find: ``` 127.0.0.1 - - [06/Sep/2015:15:20:56 -0700] "GET /v2/exercises/kotlin/bob HTTP/1.1" 500 514949 0.2138 2015-09-06 15:21:01 - JSON::GeneratorError - source sequence is illegal/malformed utf-8: ``` This is because some files generated by the build can't be served from the x-api. This is by design: the CLI does not serve binaries. To fix this, simply make sure you do a clean in your `exercism/kotlin` repo before you fetch: ``` cd ~/workspace/exercism/kotlin/exercises gradle clean cd ~/workspace/exercism/exercises exercism fetch kotlin bob ``` ================================================ FILE: _template/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: _template/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: _template/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: _template/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: _template/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: _template/src/example/kotlin/.keep ================================================ ================================================ FILE: _template/src/main/kotlin/.keep ================================================ ================================================ FILE: _template/src/test/kotlin/.keep ================================================ ================================================ FILE: bin/README.md ================================================ # Cross-track consistency Many of these scripts are shared between the Java and Kotlin tracks. If you make an update to a script in one of these tracks, please also update the same script in the other track if appropriate. Thank you! ================================================ FILE: bin/build-jq.sh ================================================ #!/usr/bin/env bash set -ex pushd bin curl --location https://github.com/stedolan/jq/releases/download/jq-1.5/jq-1.5.tar.gz >jq-1.5.tar.gz tar xvf jq-1.5.tar.gz cd jq-1.5 ./configure --disable-maintainer-mode && make mv jq .. popd ================================================ FILE: bin/fetch-configlet ================================================ #!/usr/bin/env bash # This file is a copy of the # https://github.com/exercism/configlet/blob/main/scripts/fetch-configlet file. # Please submit bugfixes/improvements to the above file to ensure that all tracks benefit from the changes. set -eo pipefail curlopts=( --silent --show-error --fail --location --retry 3 ) if [[ -n "${GITHUB_TOKEN}" ]]; then curlopts+=(--header "authorization: Bearer ${GITHUB_TOKEN}") fi get_download_url() { local os="$1" local ext="$2" local latest='https://api.github.com/repos/exercism/configlet/releases/latest' local arch case "$(uname -m)" in aarch64|arm64) arch='arm64' ;; x86_64) arch='x86-64' ;; *686*) arch='i386' ;; *386*) arch='i386' ;; *) arch='x86-64' ;; esac local suffix="${os}_${arch}.${ext}" curl "${curlopts[@]}" --header 'Accept: application/vnd.github.v3+json' "${latest}" | grep "\"browser_download_url\": \".*/download/.*/configlet.*${suffix}\"$" | cut -d'"' -f4 } main() { local output_dir if [[ -d ./bin ]]; then output_dir="./bin" elif [[ $PWD == */bin ]]; then output_dir="$PWD" else echo "Error: no ./bin directory found. This script should be ran from a repo root." >&2 return 1 fi local os case "$(uname -s)" in Darwin*) os='macos' ;; Linux*) os='linux' ;; Windows*) os='windows' ;; MINGW*) os='windows' ;; MSYS_NT-*) os='windows' ;; *) os='linux' ;; esac local ext case "${os}" in windows) ext='zip' ;; *) ext='tar.gz' ;; esac echo "Fetching configlet..." >&2 local download_url download_url="$(get_download_url "${os}" "${ext}")" local output_path="${output_dir}/latest-configlet.${ext}" curl "${curlopts[@]}" --output "${output_path}" "${download_url}" case "${ext}" in zip) unzip "${output_path}" -d "${output_dir}" ;; *) tar xzf "${output_path}" -C "${output_dir}" ;; esac rm -f "${output_path}" local executable_ext case "${os}" in windows) executable_ext='.exe' ;; *) executable_ext='' ;; esac local configlet_path="${output_dir}/configlet${executable_ext}" local configlet_version configlet_version="$(${configlet_path} --version)" echo "Downloaded configlet ${configlet_version} to ${configlet_path}" } main ================================================ FILE: bin/journey-test.sh ================================================ #!/usr/bin/env bash TRACK=kotlin TRACK_REPO="$TRACK" EXERCISES_TO_SOLVE=$@ on_exit() { echo ">>> on_exit()" cd $EXECPATH echo "<<< on_exit()" } assert_installed() { local binary=$1 echo ">>> assert_installed(binary=\"${binary}\")" if [[ "`which $binary`" == "" ]]; then echo "${binary} not found; it is required to perform this test." echo -e "Have you completed the setup instructions at https://github.com/exercism/${TRACK_REPO} ?\n" echo "PATH=${PATH}" echo "aborting." exit 1 fi echo "<<< assert_installed()" } clean() { local build_dir="$1" echo ">>> clean(build_dir=\"${build_dir}\")" # empty, absolute path, or parent reference are considered dangerous to rm -rf against. if [[ "${build_dir}" == "" || ${build_dir} =~ ^/ || ${build_dir} =~ \.\. ]] ; then echo "Value for build_dir looks dangerous. Aborting." exit 1 fi local build_path=$( pwd )/${build_dir} if [[ -d "${build_path}" ]] ; then echo "Cleaning journey script build output directory (${build_path})." rm -rf "${build_path}" fi cd exercises "$EXECPATH"/gradlew clean cd .. echo "<<< clean()" } solve_exercise() { local exercise="$1" local exercise_type="$2" echo -e "\n\n" echo "==================================================" echo "Solving ${exercise}" echo "==================================================" mkdir -p ${exercism_exercises_dir}/${TRACK} cp -R -H ${track_root}/exercises/${exercise_type}/${exercise} ${exercism_exercises_dir}/${TRACK}/${exercise} cp -R -H ${track_root}/exercises/${exercise_type}/${exercise}/.meta/src/reference/${TRACK}/* ${exercism_exercises_dir}/${TRACK}/${exercise}/src/main/${TRACK}/ pushd ${exercism_exercises_dir}/${TRACK}/${exercise} # Check that tests compile before we strip @Ignore annotations "$EXECPATH"/gradlew compileTestJava # Ensure we run all the tests (as delivered, all but the first is @Ignore'd) for testfile in `find src/test/kotlin -name "*Test.kt"`; do # Strip @Ignore annotations to ensure we run the tests (as delivered, all but the first is @Ignore'd). # Note that unit-test.sh also strips @Ignore annotations via the Gradle task copyTestsFilteringIgnores. # The stripping implementations here and in copyTestsFilteringIgnores should be kept consistent. sed 's/@Ignore\(\(.*\)\)\{0,1\}//' ${testfile} > "${tempfile}" && mv "${tempfile}" "${testfile}" done "$EXECPATH"/gradlew test echo "exit code: $?" popd } solve_all_exercises() { local exercism_exercises_dir="$1" echo ">>> solve_all_exercises(exercism_exercises_dir=\"${exercism_exercises_dir}\")" local track_root=$( pwd ) local concept_exercises=`jq -r '.exercises.concept[].slug' config.json | sort | xargs` local practice_exercises=`jq -r '.exercises.practice[].slug' config.json | sort | xargs` local total_exercises=`jq '.exercises.concept + .exercises.practice | length' config.json` local current_exercise_number=1 local tempfile="${TMPDIR:-/tmp}/journey-test.sh-unignore_all_tests.txt" mkdir -p ${exercism_exercises_dir} pushd ${exercism_exercises_dir} for exercise in $concept_exercises; do echo -e "\n\n" echo "==================================================" echo "${current_exercise_number} of ${total_exercises} -- ${exercise}" echo "==================================================" solve_exercise "${exercise}" "concept" current_exercise_number=$((current_exercise_number + 1)) done for exercise in $practice_exercises; do echo -e "\n\n" echo "==================================================" echo "${current_exercise_number} of ${total_exercises} -- ${exercise}" echo "==================================================" solve_exercise "${exercise}" "practice" current_exercise_number=$((current_exercise_number + 1)) done popd } solve_single_exercise() { local exercism_exercises_dir="$1" local exercise_to_solve="$2" local exercise_type="$3" echo ">>> solve_single_exercises(exercism_exercises_dir=\"${exercism_exercises_dir}\", exercise_to_solve=\"$exercise_to_solve\")" local track_root=$( pwd ) local tempfile="${TMPDIR:-/tmp}/journey-test.sh-unignore_all_tests.txt" mkdir -p ${exercism_exercises_dir} pushd ${exercism_exercises_dir} solve_exercise "${exercise_to_solve}" "${exercise_type}" popd } main() { # all functions assume current working directory is repository root. cd "${SCRIPTPATH}/.." local track_root=$( pwd ) local build_dir="build" local build_path="${track_root}/${build_dir}" local exercism_home="${build_path}/exercism" # fail fast if required binaries are not installed. assert_installed "jq" clean "${build_dir}" if [[ $EXERCISES_TO_SOLVE == "" ]]; then solve_all_exercises "${exercism_home}" else for exercise in $EXERCISES_TO_SOLVE; do if [ -d "${exercism_home}/exercises/concept/${exercise}" ]; then solve_single_exercise "${exercism_home}" "${exercise}" "concept" else solve_single_exercise "${exercism_home}" "${exercise}" "practice" fi done fi } ########################################################################## # Execution begins here... # If any command fails, fail the script. set -exo pipefail SCRIPTPATH=$( pushd `dirname $0` > /dev/null && pwd && popd > /dev/null ) EXECPATH=$( pwd ) # Make output easier to read in CI TERM=dumb trap on_exit EXIT main ================================================ FILE: bin/run-journey-test-from-ci.sh ================================================ #!/bin/bash contains_setup_file() { local files=$1 for file in $files; do if [[ $file == *.gradle || $file == *.gradle.kts || $file == *.sh || $file == config.json ]]; then return 0 fi done return 1 } contains_exercise() { local files=$1 for file in $files; do if [[ $file == exercises* ]]; then return 0 fi done return 1 } run_journey_test_with_modified_exercises() { local modded_files=$1 local last_modded_exercise="" local modded_exercises="" for file in $modded_files; do if [[ $file == exercises* ]] && [[ $file != exercises/settings.gradle ]] && [[ $file != exercises/build.gradle.kts ]]; then local modded_exercise=${file#exercises/} modded_exercise=${modded_exercise%%/*} if [[ $last_modded_exercise != $modded_exercise ]]; then modded_exercises=$modded_exercises$modded_exercise$'\n' fi last_modded_exercise=$modded_exercise fi done echo "Running journey test with modified exercise(s): ${modded_exercises}" bin/journey-test.sh $modded_exercises } run_journey_test_with_all_exercises() { echo "Running journey test with all exercises" bin/journey-test.sh } main() { bin/build-jq.sh local pr_files_json=`curl -s https://api.github.com/repos/exercism/kotlin/pulls/${TRAVIS_PULL_REQUEST}/files` echo "Pull request number: ${TRAVIS_PULL_REQUEST}" echo "Changes in pr json: ${pr_files_json}" # if jq fails to get the required data, then that means TRAVIS_PULL_REQUEST was not set (not run in travis-ci), # or was false (not a pull request), or the api limit was reached, or some other error occurred. # In that case, we should fall back with testing every exercise local pr_files_json_type=`echo $pr_files_json | bin/jq -r 'type'` if [[ $pr_files_json_type != "array" ]]; then echo "Didn't get pr changes from travis" run_journey_test_with_all_exercises return fi local modded_files=`echo $pr_files_json | bin/jq -r '.[].filename'` # If the changed files contain a .sh file or .gradle.kts file or config.json then we should run all the exercises if contains_setup_file "${modded_files}"; then echo "Pr changes contain setup file(s): ${modded_files}" run_journey_test_with_all_exercises return fi if contains_exercise "${modded_files}"; then echo "Pr changes contain modified exercise file(s)" run_journey_test_with_modified_exercises "${modded_files}" fi } trap 'exit 1' ERR main ================================================ FILE: bin/unit-tests.sh ================================================ #!/usr/bin/env bash set -e ./gradlew --version # Clean up any left-over files from a previous invocation, to avoid configlet # erroring when it finds an unexpected directory inside exercises. rm -rf ./exercises/build echo "" echo ">>> Running configlet..." bin/fetch-configlet bin/configlet lint pushd exercises echo "" echo ">>> Running tests..." TERM=dumb ../gradlew check compileStarterSourceKotlin --continue popd ================================================ FILE: concepts/basics/.meta/config.json ================================================ { "blurb": "TODO: add blurb for basics concept", "authors": [ "dector" ], "contributors": [] } ================================================ FILE: concepts/basics/about.md ================================================ # About Basics Kotlin is a statically typed language, designed to be fully interoperable with Java. Distinguishing it from Java, Kotlin: - has a cleaner, more concise syntax; - incorporates many features of functional languages; - has extensive support for nullable values. ## Variables Because Kotlin is statically typed, it is necessary to _know_ the type of each value at compile time. However, Kotlin's [type inference][inference] is very powerful, so _specifying_ the type is often optional. There are two ways to declare a variable. 1. `val` creates an immutable variable, and trying to change it is a compile-time error. ```kotlin val x = 42 // => 42 x = 43 // => 'val' cannot be reasssigned ``` 2. `var` creates a mutable variable. ```Kotlin var x = 42 // => 42 x = 43 // => 43 ``` Because immutable variables eliminate a common class of bugs, use of `val` is encouraged whenever possible. Also, even a `var` cannot change type: ```kotlin var x = 42 x = "foobar" // => Type mismatch: inferred type is String but Int was expected ``` To reduce visual distraction, explicit types will mostly be omitted from this syllabus. Nevertheless, it is recommended to specify types at least for: - public APIs - function signatures - where it needs documentation Some companies and organisations will require strict type safety and disallow type inference, whilst others restrict it to "simple" types, or embrace type inference fully. ```kotlin val x: Int = 42 // => 42 ``` In general, the names of variables and functions should be in `camelCase`, not `snake_case` ## Functions Declare a function with the `fun` keyword. Unlike Java, functions are not required to be part of a class. ```Kotlin fun hello(): String { return "Hello, World!" } fun add(x: Int, y: Int): Int { return x + y } ``` Some points to note: - Parentheses `()` are needed after the function name, even if the function takes no arguments. - Function arguments need to specify the type: there is no type inference (in contrast to variables). - The body of the function is enclosed in braces `{ }` (though see below). - The `return` keyword is required, if returning a value. - Semicolons `;` at the end of lines are optional, and usually omitted. - Arithmetic operators `+`, `-`, `*`, `/` are similar to most mainstream languages. However, for these very simple, "single-expression" functions, there is an abbreviated syntax: ```Kotlin // return type is usually omitted for single-expression functions fun add(x: Int, y: Int) = x + y ``` Functions can have parameters with default values. These values will be used if they are omitted where the function is invoked: ```kotlin fun ping(host: String = "localhost") { println("PING --> $host") } ping("exercism.io") // PING --> exercism.io ping() // PING --> localhost ``` Functions within Exercism will usually return a value (because of the way the test runner is structured). To use Kotlin more widely, it may be useful to know that a function which returns no value can omit the return type and the return keyword. It is then said to have a `Unit` return type: equivalent to `void` in Java and several other languages. ## Comments Single-line comments start with `//`, and the rest of the line is then ignored. Multi-line comments start with `/*` and end with `*/` ```Kotlin fun hello(): String { /* * Failing to run this program on a new installation * is considered bad luck */ return "Hello, World!" // the compiler pixies are now happy } ``` This is the same as Java. ~~~~exercism/note Because of the importance of Java interop, many Kotlin learners are at least somewhat familiar with Java. We will try to point out similarities and differences between the languages throughout the syllabus. _Please ignore this if you are a Kotlin-first learner!_ ~~~~ [inference]: https://en.wikipedia.org/wiki/Type_inference ================================================ FILE: concepts/basics/introduction.md ================================================ # Introduction Kotlin is a **statically typed** programming language developed by JetBrains. This means that the type of variables is defined at compile-time. ## Variables Similarly to other statically-typed programming languages, the type of each variable should be defined at compile time. You can avoid explicit type declarations where they can be inferred by the compiler from their context. Kotlin has immutable (`val`) and mutable (`var`) variables. The value of an immutable variable can't be changed after it's initial value is assigned. Most of the time you will use this type of variable. ```kotlin val robotName = "HAL-9000" userId = "T-1000" // This will not compile ``` A mutable variable's value can be changed one or more times: ```kotlin var index = 12 print(index) // 12 index = 100 print(index) // 100 ``` Semicolons in Kotlin are optional, except for a few special cases that will be covered later. ## Functions Functions in Kotlin are defined with the `fun` keyword and are _first-class citizens_ (not related to OOP). It means that you can declare (so-called `top-level functions`) them right in files (e.g. in Java you can define methods only in classes, not in files): ```kotlin // This is content of the Hello.kt file fun hello() {} ``` Functions can receive arguments. Each argument has a name and a type. Unlike variables, the type of arguments can't be inferred. Functions can have zero or more arguments: ```kotlin fun hello() {} fun hello(name: String) {} fun hello(name: String, age: Int) {} ``` Kotlin functions might or might not return a value: ```kotlin fun min(a: Int, b: Int): Int fun countBonuses(user: User): Bonuses fun run() {} ``` To return a value from a function, the `return` keyword is used: ```kotlin fun getName(): String { return "Alice" } ``` Functions can have parameters with default values. These values will be used if they are omitted where function is invoked: ```kotlin fun ping(host: String = "localhost") { println("PING --> $host") } ping("exercism.io") // PING --> exercism.io ping() // PING --> localhost ``` ## Comments Use `//` to define single-line comment: ```kotlin foo() // Everything after `//` will be ignored by compiler // I will be ignored too ``` or `/*` and `*/` to define multi-line comments: ```kotlin /* This this an example for a multiline comment */ ``` ================================================ FILE: concepts/basics/links.json ================================================ [] ================================================ FILE: concepts/bitwise-operations/.meta/config.json ================================================ { "authors": [ "colinleach" ], "contributors": [], "blurb": "Kotlin provides a set of bitwise operations that allow you to manipulate the individual bits of integers." } ================================================ FILE: concepts/bitwise-operations/about.md ================================================ # About Bits Binary digits ultimately map directly to the transistors in your CPU or RAM, and whether each is "on" or "off". Low-level manipulation, informally called "bit-twiddling", is particularly important in system languages. Higher-level languages like Kotlin usually abstract away most of this detail. However, a basic range of bit-level operations [is available][ref-bitwise]. ~~~~exercism/note To see human-readable binary output, nearly all the examples below need to be wrapped in an [`Integer.toBinaryString()`][web-binstring] function, or converted with `toString(radix = 2)`. This is visually distracting, so most occurrences of this function have been edited out, and the results are represented with `0b` notation. [web-binstring]: https://www.baeldung.com/kotlin/int-binary-representation ~~~~ ## Bit-shift operations `Int` or `Long` types, both signed and unsigned, can be represented as a String of 1's and 0's, and manipulated as a sequence of bits. Perhaps surprisingly, `Byte` or `Short` types are not compatible with most bitwise operations in Kotlin. All the examples below use 32-bit integers (`Int` or `UInt`). ```kotlin val ns = 0b111 // 7 decimal Integer.toBinaryString(ns) // => "111" ``` Bit-shifts move everything to the left or right by a specified number of positions. Some bits drop off one end, and the other end is padded with zeros or ones. - Left shift with `shl`: zero-padding. - Right shift with `shr` or `ushr`: zero padding for positive numbers (see later section for negative numbers). ```kotlin val ns = 0b111 // 7 decimal ns shl 1 // => 0b1110, decimal 14 ns shr 1 // => 0b11, decimal 3 ns ushr 1 // => 0b11 val nu: UInt = 0b111u // 7 unsigned nu shr 1 // => 0b11 ``` Each left-shift doubles the value, and each right-shift halves it (subject to truncation). This is more obvious in decimal representation: ```kotlin 3 shl 2 // => 12 24 shr 3 // => 3 ``` Such bit-shifting is much faster than "proper" arithmetic, making the technique very popular in low-level coding. ### Bit-shifting negative integers With _negative integers_, we need to be a bit more careful. Negative values are stored in [two's complement][wiki-2complement] form, which means that the left-most bit is 1. No problem for a left-shift, but when right-shifting how do we pad the left-most bits? ```kotlin val ns = -0b111 // => 0b11111111111111111111111111111001 // shift left: simple ns shl 1 // => 0b11111111111111111111111111110010, decimal -14 // shift right: preserves sign bit ns shr 1 // => 0b11111111111111111111111111111100, decimal -4 // unsigned shift right: left-pads with zeros ns ushr 1 // => 0b01111111111111111111111111111100, decimal 2147483644 ``` The [`shr`][ref-shr] operator performs [arithmetic shift][wiki-arithmetic], preserving the sign bit. The [`ushr`][ref-ushr] operator performs [logical shift][wiki-logical], padding with zeros as if the number was unsigned. ## Bitwise logic We saw in the [Booleans Concept][concept-booleans] that the operators `&&` (and), `||` (or) and `!` (not) are used with boolean values. There are equivalent operators `and`, `or`, `xor` ([exclusive-or][wiki-xor]) to compare the bits in two integers, and an `inv` (inversion) function to flip all the bits. ```kotlin 0b1011 and 0b0010 // bit is 1 in both numbers // => 0b0010 0b1011 or 0b0010 // bit is 1 in at least one number // => 0b1011 0b1011 xor 0b0010 // bit is 1 in exactly one number, not both // => 0b1001 0b1011.inv() // flip all bits (in a 32-bit signed Int) // => 0b11111111111111111111111111110100 ``` [ref-bitwise]: https://kotlinlang.org/docs/numbers.html#bitwise-operations [wiki-xor]: https://en.wikipedia.org/wiki/Exclusive_or [wiki-2complement]: https://en.wikipedia.org/wiki/Two%27s_complement [wiki-arithmetic]: https://en.wikipedia.org/wiki/Arithmetic_shift [wiki-logical]: https://en.wikipedia.org/wiki/Logical_shift [web-binstring]: https://www.baeldung.com/kotlin/int-binary-representation [ref-shr]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/shr.html [ref-ushr]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/ushr.html [concept-booleans]: https://exercism.org/tracks/kotlin/concepts/booleans ================================================ FILE: concepts/bitwise-operations/introduction.md ================================================ # Introduction Binary digits ultimately map directly to the transistors in your CPU or RAM, and whether each is "on" or "off". Low-level manipulation, informally called "bit-twiddling", is particularly important in system languages. Higher-level languages like Kotlin usually abstract away most of this detail. However, a basic range of bit-level operations [is available][ref-bitwise]. ## Bit-shift operations `Int` or `Long` types, signed or unsigned, can be represented as a string of 1's and 0's and manipulated as a sequence of bits. Perhaps surprisingly, `Byte` or `Short` types are not compatible with most bitwise operations in Kotlin. All the examples below use 32-bit integers (`Int` or `UInt`). ```kotlin val ns = 0b111 // 7 decimal Integer.toBinaryString(ns) // => "111" ``` Bit-shifts just move everything to the left or right by a specified number of positions. Some bits drop off one end, and the other end is padded with zeros or ones. - Left shift with `shl`: zero-padding. - Right shift with `shr` or `ushr`: zero padding for positive numbers (see later for negative numbers). ```kotlin val ns = 0b111 // 7 decimal ns shl 1 // => 0b1110, decimal 14 ns shr 1 // => 0b11, decimal 3 ns ushr 1 // => 0b11 val nu: UInt = 0b111u // 7 unsigned nu shr 1 // => 0b11 ``` Each left-shift doubles the value, and each right-shift halves it (subject to truncation). This is more obvious in decimal representation: ```kotlin 3 shl 2 // => 12 24 shr 3 // => 3 ``` Such bit-shifting is much faster than "proper" arithmetic, making the technique very popular in low-level coding. With _negative integers_, we need to be a bit more careful. Negative values are stored in [two's complement][wiki-2complement] form, which means that the left-most bit is 1. No problem for a left-shift, but when right-shifting how do we pad the left-most bits? ```kotlin val ns = -0b111 // => 0b11111111111111111111111111111001 // shift left: simple ns shl 1 // => 0b11111111111111111111111111110010, decimal -14 // shift right: preserves sign bit ns shr 1 // => 0b11111111111111111111111111111100, decimal -4 // unsigned shift right: left-pads with zeros ns ushr 1 // => 0b01111111111111111111111111111100, decimal 2147483644 ``` The `shr` operator performs [arithmetic shift][wiki-arithmetic], preserving the sign bit. The `ushr` operator performs [logical shift][wiki-logical], padding with zeros as if the number was unsigned. ## Bitwise logic We saw in the [Booleans Concept][concept-booleans] that the operators `&&` (and), `||` (or) and `!` (not) are used with boolean values. There are equivalent operators `and`, `or`, `xor` ([exclusive-or][wiki-xor]) to compare the bits in two integers, and an `inv` (inversion) function to flip all the bits. ```kotlin 0b1011 and 0b0010 // bit is 1 in both numbers // => 0b0010 0b1011 or 0b0010 // bit is 1 in at least one number // => 0b1011 0b1011 xor 0b0010 // bit is 1 in exactly one number, not both // => 0b1001 0b1011.inv() // flip all bits (in a 32-bit signed Int) // => 0b11111111111111111111111111110100 ``` [ref-bitwise]: https://kotlinlang.org/docs/numbers.html#bitwise-operations [wiki-xor]: https://en.wikipedia.org/wiki/Exclusive_or [wiki-2complement]: https://en.wikipedia.org/wiki/Two%27s_complement [wiki-arithmetic]: https://en.wikipedia.org/wiki/Arithmetic_shift [wiki-logical]: https://en.wikipedia.org/wiki/Logical_shift [concept-booleans]: https://exercism.org/tracks/kotlin/concepts/booleans ================================================ FILE: concepts/bitwise-operations/links.json ================================================ [ { "url": "https://kotlinlang.org/docs/numbers.html#bitwise-operations", "description": "Kotlin manual: bitwise operations" } ] ================================================ FILE: concepts/booleans/.meta/config.json ================================================ { "blurb": "TODO: add blurb for booleans concept", "authors": ["dector"], "contributors": [] } ================================================ FILE: concepts/booleans/about.md ================================================ # About Booleans in Kotlin are represented by the `Boolean` type, which values can be either `true` or `false`. Kotlin supports three built-in [boolean operators][reference]: `!` (negation aka NOT), `&&` (lazy conjunction aka AND), and `||` (lazy disjunction aka OR). The `&&` and `||` operators use _short-circuit evaluation_, which means that the right-hand side of the operator is only evaluated when needed. ```kotlin true || false // => true true && false // => false ``` The three boolean operators each have a different [_operator precedence_][precedence]. As a consequence, they are evaluated in this order: `!` first, `&&` second, and finally `||`. If you want to 'escape' these rules, you can enclose a boolean expression in parentheses (`()`), as the parentheses have an even higher operator precedence. ```kotlin !true && false // => false !(true && false) // => true ``` [reference]: https://kotlinlang.org/docs/reference/basic-types.html#booleans [precedence]: https://kotlinlang.org/docs/reference/grammar.html#expressions ================================================ FILE: concepts/booleans/introduction.md ================================================ # Introduction Booleans in Kotlin are represented by the `Boolean` type, which values can be either `true` or `false`. Kotlin supports three built-in [boolean operators][reference]: `!` (negation aka NOT), `&&` (lazy conjunction aka AND), and `||` (lazy disjunction aka OR). The `&&` and `||` operators use _short-circuit evaluation_, which means that the right-hand side of the operator is only evaluated when needed. ================================================ FILE: concepts/booleans/links.json ================================================ [ { "url": "https://kotlinlang.org/docs/reference/basic-types.html#booleans", "description": "reference" }, { "url": "https://kotlinlang.org/docs/reference/grammar.html#expressions", "description": "precedence" } ] ================================================ FILE: concepts/chars/.meta/config.json ================================================ { "authors": [ "colinleach" ], "contributors": [], "blurb": "Kotlin was designed from the beginning to use a large subset of Unicode characters, to represent a wide range of writing systems." } ================================================ FILE: concepts/chars/about.md ================================================ # About chars This is potentially a _big_ subject! It is possible to write a long book about it, and several people have done so (search Amazon for "unicode book" to see some examples). ## A very brief history Handling characters in computers was much simpler in earlier decades, when programmers assumed that English was the only important language. So: 26 letters, upper and lower case, 10 digits, several punctuation marks, plus a code (0x07) to ring a bell, and it all fitted into 7 bits: the [ASCII][wiki-ascii] character set. Naturally, people started asking what about à, ä and Ł, then other people started asking about ऄ, ஹ and ญ, and young people wanted emojis 😱. What to do? To cut a long story short, many smart and patient people had to serve on committees for years, working out the details of the [Unicode][web-unicode] character set, and of encodings such as [UTF-8][wiki-utf-8], and lots of software needed a _very_ complicated rewrite. Also, lots of new bugs were introduced. To prevent _everything_ breaking, the Unicode/UTF-8 design ensures that the first 127 codes are identical to ASCII _(even the bell)_. ## Characters in Kotlin Languages designed after about 2005 have the huge advantage that a reasonably stable Unicode standard already existed. Kotlin (first released in 2011) was able to assume that users would use a variety of (human) languages, and would need Unicode to express them. ~~~~exercism/advanced [Characters][ref-char] in Kotlin are 16-bit (UTF-16) [`codepoints`][wiki-codepoint], the same as a JVM `char`. This is enough to express most written alphabets, but not the entire range of emojis. The full Unicode standard uses up to six bytes (48 bits) per character (called a [`grapheme`][wiki-grapheme]). Kotlin `Strings` support this full standard by using multiple codepoints per character, when necessary. For example, 😱 would be `\uD83D` and `\uDE31`. Unfortunately, Java has no built-in grapheme support, and for compatibility neither does Kotlin. [wiki-codepoint]: https://en.wikipedia.org/wiki/Code_point [wiki-grapheme]: https://en.wikipedia.org/wiki/Grapheme [ref-char]: https://kotlinlang.org/docs/characters.html ~~~~ Character literals are written in single-quotes, and are distinct from strings written in double quotes. This is probably obvious to people from the C/C++ world, but potentially confusing to Python and JavaScript programmers. ```kotlin val a = 'a' a::class.qualifiedName // => kotlin.Char a.code // => 97 val jha = 'झ' // Devanagari alphabet jha.code // => 2333 val heart = '❤' // heart emoji heart.code // => 10084 Char.MAX_VALUE.code // => 65535 (64k, the largest code point allowed) val not_char = 'abc' // => Too many characters in a character literal. ``` Converting between `Char` and `Int` is straightforward: ```kotlin a.code // => 97 Char(97) // => 'a' ``` The compiler allows _some_ forms of integer arithmetic on `Char`s: ```kotlin 'a' + 5 // => 'f' 'c' - 'a' // => 2 'c' + 'a' // => error! 'f' + ('A' - 'a') // => 'F' (same as 'f'.uppercase() 'f'.dec() // => 'e' (decrement) 'f'.inc() // => 'g' (increment) ``` ## Some functions for `Char` As always, there are far too [many functions][ref-char-lib] to discuss here, so this is just a selection. - For appropriate alphabets, change case with [`uppercase()`][ref-uppercase] and [`lowercase()`][ref-lowercase]. - Test case with [`isUpperCase()`][ref-isuppercase] and [`isLowerCase()`][ref-islowercase]. - Test character type with: - [`isLetter()`][ref-isletter], covers many alphabets (the Lu, Ll, Lt, Lm, and Lo categories in unicode) - [`isDigit()`][ref-isdigit], in range 0..9 (the Nd category in unicode) - `isLetterOrDigit()`, combines the previous two - [`isWhitespace()`][ref-iswhitespace], any whitespace character (the Cc, Zp, Zl, and Zs categories in unicode) ```kotlin 'झ'.isLetter() // => true 'A'.isLowerCase() // => false '4'.isDigit() // => true '\t'.isWhitespace() // => true (tab character) ``` Also, [regular expressions][ref-regex] (which will be the subject of a later Concept) allow powerful search and manipulation. ## Char List and String interconversions To convert from a `String` to a `List` of `Char`s, we can use `toList()`. To convert a `List` of `Char`s to a `String`, there is the [`joinToString()`][ref-jointostring] function, which takes a separator (often the empty string) as argument. ```kotlin val kt = "kotlin".toList() // => [k, o, t, l, i, n] kt.joinToString("") // => "kotlin" kt.joinToString("_") // => "k_o_t_l_i_n" ``` Note that `joinToString()` operates on a List or Array. To _cast_ a single `Char` to a 1-character string, use `toString()`. ```kotlin 'a'.toString() // => "a" ``` To check if a character is present in a `String`, or a `Char` list or array, we have `in`, which maps to the [`contains()`][ref-contains] function. ```kotlin val clist = "kotlin".toList() // => [k, o, t, l, i, n] 't' in clist // => true 't' in "kotlin" // => true ``` [ref-char]: https://kotlinlang.org/docs/characters.html [ref-char-lib]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-char/ [wiki-ascii]: https://en.wikipedia.org/wiki/ASCII [web-unicode]: https://home.unicode.org/ [wiki-utf-8]: https://en.wikipedia.org/wiki/UTF-8 [ref-uppercase]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/uppercase.html [ref-lowercase]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/lowercase.html [ref-isuppercase]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-upper-case.html [ref-islowercase]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-lower-case.html [ref-isletter]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-letter.html [ref-isdigit]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-digit.html [ref-iswhitespace]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-whitespace.html [ref-jointostring]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/join-to-string.html [ref-contains]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/contains.html [ref-regex]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-regex/ ================================================ FILE: concepts/chars/introduction.md ================================================ # Introduction This is potentially a _big_ subject! It is possible to write a long book about it, and several people have done so (search Amazon for "unicode book" to see some examples). ## A very brief history Handling characters in computers was much simpler in earlier decades, when programmers assumed that English was the only important language. So: 26 letters, upper and lower case, 10 digits, several punctuation marks, plus a code (0x07) to ring a bell, and it all fitted into 7 bits: the [ASCII][wiki-ascii] character set. Naturally, people started asking what about à, ä and Ł, then other people started asking about ऄ, ஹ and ญ, and young people wanted emojis 😱. What to do? To cut a long story short, many smart and patient people had to serve on committees for years, working out the details of the [Unicode][web-unicode] character set, and of encodings such as [UTF-8][wiki-utf-8], and lots of software needed a _very_ complicated rewrite. Also, lots of new bugs were introduced. To prevent _everything_ breaking, the Unicode/UTF-8 design ensures that the first 127 codes are identical to ASCII _(even the bell)_. ## Characters in Kotlin Languages designed after about 2005 have the huge advantage that a reasonably stable Unicode standard already existed. Kotlin (first released in 2011) was able to assume that users would use a variety of (human) languages, and would need Unicode to express them. Character literals are written in single-quotes, and are distinct from strings written in double quotes. This is probably obvious to people from the C/C++ world, but potentially confusing to Python and JavaScript programmers. ```kotlin val a = 'a' a::class.qualifiedName // => kotlin.Char a.code // => 97 val jha = 'झ' // Devanagari alphabet jha.code // => 2333 val heart = '❤' // heart emoji heart.code // => 10084 Char.MAX_VALUE.code // => 65535 (64k, the largest code point allowed) ``` Converting between `Char` and `Int` is simple: ```kotlin a.code // => 97 (a.toInt() is deprecated) Char(97) // => 'a' ``` The compiler allows _some_ forms of integer arithmetic on `Char`s: ```kotlin 'a' + 5 // => 'f' 'c' - 'a' // => 2 'c' + 'a' // => error! 'f' + ('A' - 'a') // => 'F' (same as 'f'.uppercase() 'f'.dec() // => 'e' (decrement) 'f'.inc() // => 'g' (increment) ``` ## Some functions for `Char` As always, there are far too [many functions][ref-char-lib] to discuss here, so this is just a selection. - For appropriate alphabets, change case with [`uppercase()`][ref-uppercase] and [`lowercase()`][ref-lowercase]. - Test case with [`isUpperCase()`][ref-isuppercase] and [`isLowerCase()`][ref-islowercase]. - Test character type with: - [`isLetter()`][ref-isletter], covers many alphabets - [`isDigit()`][ref-isdigit], in range 0..9 - `isLetterOrDigit()`, combines the previous two - [`isWhitespace()`][ref-iswhitespace], any whitespace character ```kotlin 'झ'.isLetter() // => true 'A'.isLowerCase() // => false '4'.isDigit() // => true '\t'.isWhitespace() // => true (tab character) ``` ## Char List and String interconversions For String to Char List, we can use `toList()`. For Char List to String, there is the [`joinToString()`][ref-jointostring] function, which takes a separator (often the empty string) as argument. ```kotlin val kt = "kotlin".toList() // => [k, o, t, l, i, n] kt.joinToString("") // => "kotlin" kt.joinToString("_") // => "k_o_t_l_i_n" ``` Note that `joinToString()` operates on a List or Array. To _cast_ a single `Char` to a 1-character string, use `toString()`. ```kotlin 'a'.toString() // => "a" ``` To check if a character is present in a `String`, or a `Char` list or array, we have `in`, which maps to the [`contains()`][ref-contains] function. ```kotlin val clist = "kotlin".toList() // => [k, o, t, l, i, n] 't' in clist // => true 't' in "kotlin" // => true ``` [ref-char]: https://kotlinlang.org/docs/characters.html [ref-char-lib]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-char/ [wiki-ascii]: https://en.wikipedia.org/wiki/ASCII [web-unicode]: https://home.unicode.org/ [wiki-utf-8]: https://en.wikipedia.org/wiki/UTF-8 [ref-uppercase]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/uppercase.html [ref-lowercase]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/lowercase.html [ref-isuppercase]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-upper-case.html [ref-islowercase]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-lower-case.html [ref-isletter]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-letter.html [ref-isdigit]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-digit.html [ref-iswhitespace]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/is-whitespace.html [ref-jointostring]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/join-to-string.html [ref-contains]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/contains.html [ref-regex]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-regex/ ================================================ FILE: concepts/chars/links.json ================================================ [ { "url": "https://kotlinlang.org/docs/characters.html", "description": "Kotlin introduction to characters." }, { "url": "https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-char/", "description": "Char type and functions" } ] ================================================ FILE: concepts/conditionals/.meta/config.json ================================================ { "authors": [ "colinleach" ], "contributors": [], "blurb": "The conditionals `if`, `else if` and `else` are used to control the flow of execution and make decisions in a program." } ================================================ FILE: concepts/conditionals/about.md ================================================ # About conditionals ## Comparison operators [Comparison operators][operators] are similar to many other languages, with a few extensions. For equality, the operators are `==` (equal) and `!=` (not equal). ```Kotlin val txt = "abc" txt == "abc" // => true txt != "abc" // => false ``` Additionally, the `===` and `!==` operators test for ["referential equality"][referential-equality]: `a === b` if and only if `a` and `b` point to the same object. This should make more sense later in the syllabus. The greater/less than operators are also conventional. ```Kotlin 1 < 3 // => true 3 > 3 // => false 3 <= 3 // => true 4 >= 3 // => true ``` ## Branching with `if` This is the full form of an [`if` expression][if-else]: ```Kotlin if (conditional1) { // something... } else if (conditional2) { // something... } else { // something... } ``` - Parentheses `()` around each conditional are required. - A conditional must evaluate to a Boolean `true` or `false`. Kotlin has no concept of "truthy" and "falsy" as found in some languages. - Braces `{}` are optional, if there is only a single expression. - Both `else if` and `else` are optional, and there can be multiple `else if` blocks. ## Alternatives? By deliberate choice, Kotlin does _not_ have the ternary operator `? :` found in Java. A concise form of `if ... else` is preferred: ```Kotlin val result = if (isOk) goodValue else badValue return if (isOK) goodValue else badValue ``` Unlike Ruby, the concise `if ... else` form *always* needs an `else` and thus cannot be used as a guard statement: ```kotlin return 42 if (isOk) // Syntax error: Unexpected tokens (use ';' to separate expressions on the same line). // Syntax error: Expecting an expression. return if (isOk) true // 'if' must have both main and 'else' branches when used as an expression. ``` Note that in Kotlin, `if` is an [_expression_][expression] returning a value. It is not a [_statement_][statement] as in Java. We will see in a later Concept that Kotlin has a powerful [`when`][when] construct, intended to replace long chains of `else if` clauses with pattern matching. [operators]: https://kotlinlang.org/docs/keyword-reference.html#operators-and-special-symbols [referential-equality]: https://kotlinlang.org/docs/equality.html#floating-point-numbers-equality [if-else]: https://kotlinlang.org/docs/control-flow.html#if-expression [when]: https://kotlinlang.org/docs/control-flow.html#when-expressions-and-statements [expression]: https://en.wikipedia.org/wiki/Expression_(computer_science) [statement]: https://en.wikipedia.org/wiki/Statement_(computer_science) ================================================ FILE: concepts/conditionals/introduction.md ================================================ # Introduction ## Comparison operators Comparison operators are similar to many other languages. For equality, the operators are `==` (equal) and `!=` (not equal). ```Kotlin val txt = "abc" txt == "abc" // => true txt != "abc" // => false ``` The greater/less than operators are also conventional. ```Kotlin 1 < 3 // => true 3 > 3 // => false 3 <= 3 // => true 4 >= 3 // => true ``` ## Branching with `if` This is the full form of an `if` expression: ```Kotlin if (conditional1) { // something... } else if (conditional2) { // something... } else { // something... } ``` - Parentheses `()` around each conditional are required. - A conditional must evaluate to a Boolean `true` or `false`. Kotlin has no concept of "truthy" and "falsy" as found in some languages. - Braces `{}` are optional, if there is only a single expression. - Both `else if` and `else` are optional, and there can be multiple `else if` blocks. ## Alternatives? By deliberate choice, Kotlin does _not_ have the ternary operator `? :` found in Java. A concise form of `if ... else` is preferred: ```Kotlin return if (isOK) goodValue else badValue ``` ================================================ FILE: concepts/conditionals/links.json ================================================ [ { "url": "https://kotlinlang.org/docs/keyword-reference.html#operators-and-special-symbols", "description": "Operators reference." }, { "url": "https://kotlinlang.org/docs/control-flow.html#if-expression", "description": "Control flow introduction." }, { "url": "https://kotlinlang.org/docs/coding-conventions.html#control-flow-statements", "description": "Coding conventions." } ] ================================================ FILE: concepts/nullability/.meta/config.json ================================================ { "authors": [ "colinleach" ], "contributors": [], "blurb": "Kotlin provides optional nullable types, plus functionality to make nullability safe and convenient to use." } ================================================ FILE: concepts/nullability/about.md ================================================ # About Nullability In an ideal world, we could rely on everything being nicely defined, with concrete values and no gaps. This conflicts with our everyday experience, and thus many programming languages have a way to represent the absence of a value: null or NULL, nil, None, nothing... This was easy to introduce (back in 1965), but soon led to regrets. The inventor later called it his ["Billion Dollar Mistake"][web-mistake]. In recent decades, language designers have explored many ways to make nulls available but (mostly) safe. Kotlin has a few [general principles][ref-null-safety], which [differ significantly from Java][ref-java2kotlin]. _The differences mean that Kotlin has special functionality to deal with Java interop, though details are beyond the scope of this Concept._ - Kotlin has a special `null` value. - All types _default_ to being non-nullable (i.e. can not be `null`) . - All types can be _nullable_, but this must be explicitly done. - Functions which might fail with an exception are likely to have a variant with a nullable return value. - Special, highly terse syntax tries to make testing for and responding to nulls as easy as possible. ## Creating nullable variables A type can be made [nullable][ref-nullable-type] by adding the `?` suffix (e.g. `String?` instead of `String`). ```kotlin var a = "Kotlin" // inferred type is String a = null // => Error: Null can not be a value of a non-null type String var b: String? = "Kotlin" // nullable type b = null // => b is now null b == null // => true ``` ## Useful operators and functions ### The [safe call operator][ref-safe-call] `?.` For a non-nullable `String`, we can get the `.length` property. A nullable `String?` fails with the same syntax, but using `?.length` allows for the possibility of a `null`. The return type is `Int?`. ```kotlin var a = "Kotlin" a.length // => 6 // b is still null b.length // => Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? b?.length // => null a?.length // => 6 ``` As we saw in the last line above, `?.` also works with non-nullable types. ### The [Elvis operator][ref-elvis] `?:` Extending the idea of the safe-call operator, the [Elvis operator][wiki-elvis] lets us supply a default value to replace `null`. ```kotlin // b is still null b?.length ?: -1 // => -1, in place of null a?.length ?: -1 // => 6, as before ``` ### [Not-null assertion operator][ref-not-null] `!!` With this operator, a nullable type is forced to be treated as non-null, when the programmer is confident about this. Perhaps we sometimes understand the program logic better than an over-cautious compiler? ```kotlin // b is still a String? b = "Kotlin?" b!!.length // => 7 ``` The responsibility is now on us: if `b` is still `null` we get a `NullPointerException`. ### [Let function][ref-let] `?.let` If passing a nullable item to a block of code, we could do specific null checks `if (item != null) { do something }`. It is simpler and more idiomatic to use `item?.let { do something }`, The `do something` will only execute when `item` is not null. ### Functions of type `somethingOrNone()` Some functions may fail, for example when asking for an invalid index in a string or list. Rather than throwing an exception, we could use the [`...OrNull` variant][ref-elem-at-or-null] of the function, to get (in this case) an `Int?` return value. ```kotlin val str = "Kotlin" str.elementAtOrNull(10) // => null str.elementAt(10) // => StringIndexOutOfBoundsException: String index out of range: 10 ``` [ref-java2kotlin]: https://kotlinlang.org/docs/java-to-kotlin-nullability-guide.html [web-mistake]: https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/ [ref-null-safety]: https://kotlinlang.org/docs/null-safety.html [ref-elvis]: https://kotlinlang.org/docs/null-safety.html#elvis-operator [wiki-elvis]: https://en.wikipedia.org/wiki/Elvis_operator [ref-nullable-type]: https://kotlinlang.org/docs/null-safety.html#nullable-types-and-non-nullable-types [ref-safe-call]: https://kotlinlang.org/docs/null-safety.html#safe-call-operator [ref-not-null]: https://kotlinlang.org/docs/null-safety.html#not-null-assertion-operator [ref-let]: https://kotlinlang.org/docs/null-safety.html#let-function [ref-elem-at-or-null]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/element-at-or-null.html ================================================ FILE: concepts/nullability/introduction.md ================================================ # Introduction In an ideal world, we could rely on everything being nicely defined, with concrete values and no gaps. This conflicts with our everyday experience, and thus many programming languages have a way to represent the absence of a value: null or NULL, nil, None, nothing... This was easy to introduce (back in 1965), but soon led to regrets. The inventor later called it his "Billion Dollar Mistake". In recent decades, language designers have explored many ways to make nulls available but (mostly) safe. Kotlin has a few [general principles][ref-null-safety], which differ significantly from Java. - Kotlin has a special `null` value. - All types _default_ to being non-nullable. - Most types can be _made_ nullable, but the programmer must explicitly order this. - Functions which might fail with an exception are likely to have a variant with a nullable return value. - Special, highly terse syntax tries to make testing for and responding to nulls as easy as possible. ## Creating nullable variables Standard types generally have a nullable equivalent, with a `?` suffix: for example `String?` instead of `String`. ```kotlin var a = "Kotlin" // inferred type is String a = null // => Error: Null can not be a value of a non-null type String var b: String? = "Kotlin" // nullable type b = null // => b is now null b == null // => true ``` ## Useful operators and functions ### The safe call operator `?.` For a non-nullable `String`, we can get the `.length` property. A nullable `String?` fails with the same syntax, but using `?.length` allows for the possibility of a `null`. The return type is `Int?`. ```kotlin var a = "Kotlin" a.length // => 6 // b is still null b.length // => Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? b?.length // => null a?.length // => 6 ``` As we saw in the last line above, `?.` also works with non-nullable types. ### The Elvis operator `?:` Extending the idea of the safe-call operator, the [Elvis operator][wiki-elvis] lets us supply a default value to replace `null`. ```kotlin // b is still null b?.length ?: -1 // => -1, in place of null a?.length ?: -1 // => 6, as before ``` ### Not-null assertion operator `!!` With this operator, a nullable type is forced to be treated as non-null, when the programmer is confident about this. Perhaps we sometimes understand the program logic better than an over-cautious compiler? ```kotlin // b is still a String? b = "Kotlin?" b!!.length // => 7 ``` The responsibility is now on us: if `b` is still `null` we get a `NullPointerException`. ### Let function `?.let` If passing a nullable item to a block of code, we could do specific null checks `if (item != null) { do something }`. It is simpler and more idiomatic to use `item?.let { do something }`, The `do something` will only execute when `item` is not null. ### Functions of type `somethingOrNone()` Some functions may fail, for example when asking for an invalid index in a string or list. Rather than throwing an exception, we could use the `...OrNull` variant of the function, to get (in this case) an `Int?` return value. ```kotlin val str = "Kotlin" str.elementAtOrNull(10) // => null str.elementAt(10) // => StringIndexOutOfBoundsException: String index out of range: 10 ``` [web-mistake]: https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/ [ref-null-safety]: https://kotlinlang.org/docs/null-safety.html [wiki-elvis]: https://en.wikipedia.org/wiki/Elvis_operator ================================================ FILE: concepts/nullability/links.json ================================================ [ { "url": "https://kotlinlang.org/docs/null-safety.html", "description": "Kotlin introduction to null safety." }, { "url": "https://kotlinlang.org/docs/java-to-kotlin-nullability-guide.html", "description": "Nullability guide for Java to Kotlin migration." } ] ================================================ FILE: concepts/strings/.meta/config.json ================================================ { "authors": [ "colinleach" ], "contributors": [], "blurb": "Strings are an immutable sequence of Unicode characters." } ================================================ FILE: concepts/strings/about.md ================================================ # About Strings A [`string`][ref-string] in Kotlin is an immutable sequence of Unicode characters. [`Immutable`][wiki-immutable] means that any operation on a string must return a new string: the original string can never change. [`Unicode`][wiki-unicode] means that most of the world's writing systems can be represented, but (in contrast to older languages such as C) there is no 1:1 mapping between characters and bytes. This will be discussed further in the [`Chars`][concept-chars] Concept. A string is surrounded by double-quotes `" "`. Some characters need escaping: `\\`, plus the usual non-printing characters such as `\t` (tab) and `\n` (newline). ```kotlin val s = "Escape backslash \\." // Escape backslash \. ``` Multi-line strings are surrounded by 3 double-quotes, and can contain arbitrary text (no need for escaping). ```kotlin val multi = """I'm a multi-line string with special characters \ \t """ //I'm a // multi-line // string with special characters \ \t ``` Use [trimIndent][trimIndent-doc] to remove the common indenting from the lines. This is useful for formatting the string: ```kotlin val multi = """ I'm a multi-line string""".trimIndent() //I'm a // multi-line //string ``` Alternatively, [trimMargin][trimMargin-doc] lets you specify a delimiter. Each line in the `String` then begins after the delimiter. The delimiter defaults to `|`, but you can specify a different delimiter as a parameter. For example: ```kotlin val multi = """ |I'm a | multi-line |string""".trimMargin() //I'm a // multi-line //string val multi2 = """ start>I'm a start> multi-line start>string""".trimMargin("start>") //I'm a // multi-line //string ``` Strings can be concatenated with `+`, but this is best limited to short and simple cases. There are other and often better options. ## String templates [`Templates`][ref-templates] refers to what some other languages call "interpolation". If a string contains a dollar sign `$`, followed by an identifier, or contains braces (`{expression}`) surrounding an expression, those are substituted by respectively the value or the result of the expression. ```kotlin val x = 42 val st = "x is $x, x squared is {x * x}" // x is 42, x squared is 1764 ``` ## String formatting On the JVM platform (only), `String.format()` allows more precise formatting than string templates, with [syntax][web-formats] similar to the (_very old!_) [`printf`][wiki-printf] functions. ```kotlin String.format("%s %.3f", "π ≈", 3.14159) //π ≈ 3.142 ``` ~~~~exercism/advanced Kotlin can be compiled to several different targets: the Java Virtual Machine, JavaScript, native binaries for Linux, Windows, Android and Apple, plus two variants of WebAssembly. Essentially the same code can be used for each, but different capabilities in the target platforms mean some differences in which standard library functions are supported. Exercism currently uses the JVM for testing. ~~~~ ## String functions Kotlin provides _many_ [`functions`][ref-string-functions] to manipulate strings. Mostly, these are [`extensions functions`][ref-extensions] rather than members of the `String` class, though this has little effect on how we use them. ~~~~exercism/note Kotlin's rather complex [documentation][ref-string-functions] pages hide extension functions in the default view. At moment of writing this, the most valuable content is hidden in a tab named `Members & Extensions`. Click it to expand this section and see all the members and extensions available on the `String` class. [ref-string-functions]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/ ~~~~ The following example shows just a small selection of what is available: ```kotlin val str = "Hello World!" str.length // => 12 (a property, not a function) str.elementAt(6) // => W str.elementAtOrNull(20) // => null (index out of range) str.substring(6, 11) // => "World" str.substringAfter(" ") // => "World!" str.lowercase() // => "hello world!" str.uppercase() // => "HELLO WORLD!" str.startsWith("Hel") // => true str.endsWith("xyz") // => false str.indexOf("0") // => 4 str.toCharArray() // => [H, e, l, l, o, , W, o, r, l, d, !] "42".toInt() + 1 // => 43 (parsing; see also toFloat) "Howdy! ".trim() // => "Howdy" ``` ## Building a string Sometimes a long string needs to be built up in stages, for example within a loop. Concatenating strings with `+` soon becomes neither elegant nor performant: immutability means that there is a _lot_ of copying required. Kotlin has various more efficient ways to combine multiple string: - String templates, described above. - [`joinToString()][ref-jointostring], which will be covered in the [Lists][concept-lists] Concept. - Java's [`StringBuilder`][ref-stringbuilder], which is not regarded as particularly idiomatic Kotlin. - Kotlin's [`buildString()`][ref-buildstring], which wraps `StringBuilder` in a more concise and idiomatic syntax. This takes string-building logic as a lambda argument, which will be discussed in a later Concept. In essence, a `StringBuilder` is a list-like structure, with many convenient methods. This is a small selection: - [`append()`][ref-sb-append] to add to the end. - [`insert()`][ref-sb-insert] to add at a specified position. - [`deleteAt()`][ref-sb-deleteat] and [`deleteRange()`][ref-sb-deleterange] to remove from specified position(s). - `toString()` to convert to a normal string at the end: concatenating everything in a single, performant operation. ```kotlin // Available, not recommended val sb = StringBuilder() sb.append("Hello ") sb.append("World!") sb.toString() //Hello World! ``` A `buildString()` example, using syntax from later Concepts: ```kotlin val countDown = buildString { for (i in 5 downTo 1) { append(i) append("_") } } // countDown is "5_4_3_2_1_" ``` [ref-string]: https://kotlinlang.org/docs/strings.html [wiki-immutable]: https://en.wikipedia.org/wiki/Immutable_object [wiki-unicode]: https://en.wikipedia.org/wiki/Unicode [web-formats]: https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#summary [wiki-printf]: https://en.wikipedia.org/wiki/Printf [ref-stringbuilder]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-string-builder/ [ref-extensions]: https://kotlinlang.org/docs/extensions.html#extensions.md [ref-string-functions]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/ [concept-chars]: https://exercism.org/tracks/kotlin/concepts/chars [concept-lists]: https://exercism.org/tracks/kotlin/concepts/lists [ref-templates]: https://kotlinlang.org/docs/strings.html#string-templates [ref-sb-append]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-string-builder/#9100522%2FFunctions%2F-705004581 [ref-sb-insert]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-string-builder/#-132863384%2FFunctions%2F-705004581 [ref-sb-deleteat]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-string-builder/#-386007892%2FFunctions%2F-956074838 [ref-sb-deleterange]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-string-builder/#-1622040372%2FFunctions%2F-956074838 [ref-buildstring]: https://kotlinlang.org/docs/java-to-kotlin-idioms-strings.html#build-a-string [ref-jointostring]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/join-to-string.html [trimIndent-doc]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/trim-indent.html [trimMargin-doc]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/trim-margin.html ================================================ FILE: concepts/strings/introduction.md ================================================ # Introduction A [`string`][ref-string] in Kotlin is an immutable sequence of Unicode characters. [`Immutable`][wiki-immutable] means that any operation on a string must return a new string: the original string can never change. [`Unicode`][wiki-unicode] means that most of the world's writing systems can be represented, but (in contrast to older languages such as C) there is no 1:1 mapping between characters and bytes. A string is surrounded by double-quotes `" "`. Some characters need escaping: `\\`, plus the usual non-printing characters such as `\t` (tab) and `\n` (newline). ```kotlin val s = "Escape backslash \\." // Escape backslash \. ``` Multi-line strings are surrounded by 3 double-quotes, and can contain arbitrary text (no need for escaping). ```kotlin val multi = """I'm a multi-line string with special characters \ \t """ //I'm a // multi-line // string with special characters \ \t ``` Use [trimIndent][trimIndent-doc] to remove the common indenting from the lines. This is useful for formatting the string: ```kotlin val multi = """ I'm a multi-line string""".trimIndent() //I'm a // multi-line //string ``` Alternatively, [trimMargin][trimMargin-doc] lets you specify a delimiter. Each line in the `String` then begins after the delimiter. The delimiter defaults to `|`, but you can specify a different delimiter as a parameter. For example: ```kotlin val multi = """ |I'm a | multi-line |string""".trimMargin() //I'm a // multi-line //string val multi2 = """ start>I'm a start> multi-line start>string""".trimMargin("start>") //I'm a // multi-line //string ``` Strings can be concatenated with `+`, but this is best limited to short and simple cases. There are other and often better options. ## String templates This refers to what some other languages call "interpolation". If a string contains a dollar sign `$`, followed by an identifier, or contains braces (`{expression}`) surrounding an expression, those are substituted by respectively the value or the result of the expression. ```kotlin val x = 42 val st = "x is $x, x squared is {x * x}" // x is 42, x squared is 1764 ``` The braces `{ }` are needed around expressions when parsing would otherwise be ambiguous. In general, use of string templates is a more efficient and idiomatic way to combine strings than using `+`. ## String functions Kotlin provides _many_ [`functions`][ref-string-functions] to manipulate strings. Mostly, these are [`extensions functions`][ref-extensions] rather than members of the `String` class, though this has little effect on how we use them. ~~~~exercism/note Kotlin's rather complex [documentation][ref-string-functions] pages hide extension functions in the default view. Be sure to click `Members & Extensions` to expand this section. [ref-string-functions]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/ ~~~~ The following examples show just a small selection of what is available: ```kotlin val str = "Hello World!" str.length // => 12 (a property, not a function) str.elementAt(6) // => W str.elementAtOrNull(20) // => null (index out of range) str.substring(6, 11) // => "World" str.substringAfter(" ") // => "World!" str.lowercase() // => "hello world!" str.uppercase() // => "HELLO WORLD!" str.startsWith("Hel") // => true str.endsWith("xyz") // => false str.indexOf("0") // => 4 str.toCharArray() // => [H, e, l, l, o, , W, o, r, l, d, !] "42".toInt() + 1 // => 43 (parsing; see also toFloat) "Howdy! ".trim() // => "Howdy" ``` [ref-string]: https://kotlinlang.org/docs/strings.html [wiki-immutable]: https://en.wikipedia.org/wiki/Immutable_object [wiki-unicode]: https://en.wikipedia.org/wiki/Unicode [ref-stringbuilder]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-string-builder/ [ref-extensions]: https://kotlinlang.org/docs/extensions.html#extensions.md [ref-string-functions]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/ [trimIndent-doc]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/trim-indent.html [trimMargin-doc]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/trim-margin.html ================================================ FILE: concepts/strings/links.json ================================================ [ { "url": "https://kotlinlang.org/docs/strings.html", "description": "Kotlin string introduction" }, { "url": "https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/", "description": "String functions" }, { "url": "https://kotlinlang.org/docs/strings.html#string-templates", "description": "String Templates" } ] ================================================ FILE: config.json ================================================ { "language": "Kotlin", "slug": "kotlin", "active": true, "status": { "concept_exercises": false, "test_runner": true, "representer": false, "analyzer": false }, "blurb": "Kotlin is a pragmatic programming language for JVM and Android that combines OO and functional features and is focused on interoperability, safety, clarity and tooling support.", "version": 3, "online_editor": { "indent_style": "space", "indent_size": 4, "highlightjs_language": "kotlin" }, "test_runner": { "average_run_time": 4 }, "files": { "solution": [ "src/main/kotlin/%{pascal_slug}.kt" ], "test": [ "src/test/kotlin/%{pascal_slug}Test.kt" ], "example": [ ".meta/src/reference/kotlin/%{pascal_slug}.kt" ], "exemplar": [ ".meta/src/reference/kotlin/%{pascal_slug}.kt" ] }, "exercises": { "concept": [ { "slug": "lucians-luscious-lasagna", "name": "Lucian's Luscious Lasagna", "uuid": "de14936d-28d7-4531-9761-69deba31a7ca", "concepts": [ "basics" ], "prerequisites": [], "status": "wip" }, { "slug": "annalyns-infiltration", "name": "Annalyn's Infiltration", "uuid": "5a0af671-2549-411c-860a-f36859b429e5", "concepts": [ "booleans" ], "prerequisites": [ "basics" ], "status": "wip" }, { "slug": "log-levels", "name": "log-levels", "uuid": "ef54c5e6-7d31-42d1-a300-e405169dbd7f", "concepts": [ "strings" ], "prerequisites": [ "basics" ], "status": "wip" } ], "practice": [ { "slug": "accumulate", "name": "Accumulate", "uuid": "86015770-603b-44cf-aedf-f2a7cf79c841", "practices": [], "prerequisites": [], "difficulty": 1, "status": "deprecated", "topics": [ "lists" ] }, { "slug": "binary", "name": "Binary", "uuid": "def44955-c048-4b74-8777-2fb7d779b09e", "practices": [], "prerequisites": [], "difficulty": 1, "status": "deprecated", "topics": [ "strings" ] }, { "slug": "hello-world", "name": "Hello World", "uuid": "58c16459-348a-4536-8228-43379174735e", "practices": [], "prerequisites": [], "difficulty": 1, "topics": [ "strings" ] }, { "slug": "hexadecimal", "name": "Hexadecimal", "uuid": "13b1a62e-8e0e-4d57-b8c9-341b41f25cf5", "practices": [], "prerequisites": [], "difficulty": 1, "status": "deprecated", "topics": [ "string", "integers" ] }, { "slug": "reverse-string", "name": "Reverse String", "uuid": "95d495a6-b1a2-42d5-8190-443d6f94e80b", "practices": [], "prerequisites": [], "difficulty": 1, "topics": [ "strings" ] }, { "slug": "strain", "name": "Strain", "uuid": "8ae8492d-620c-4446-9928-5b4d78d496d9", "practices": [], "prerequisites": [], "difficulty": 1, "status": "deprecated", "topics": [ "arrays", "filtering" ] }, { "slug": "bob", "name": "Bob", "uuid": "f3713067-7f37-4dd6-a189-c80f46dab8ec", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "booleans", "conditionals", "strings" ] }, { "slug": "collatz-conjecture", "name": "Collatz Conjecture", "uuid": "ab52d0f4-a001-4d44-951e-0cfc396374f3", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "conditionals", "exception_handling", "integers", "math", "recursion" ] }, { "slug": "darts", "name": "Darts", "uuid": "c2b49ff6-e7bf-40bb-b619-9cdfaa43c065", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "pattern_matching", "conditionals", "math" ] }, { "slug": "eliuds-eggs", "name": "Eliud's Eggs", "uuid": "88e7d43f-87f8-4c00-a463-f1593d725e18", "practices": [], "prerequisites": [], "difficulty": 2 }, { "slug": "etl", "name": "ETL", "uuid": "f0f297f2-429f-4626-8b7f-0706a1e8f255", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "lists", "maps", "transforming" ] }, { "slug": "grains", "name": "Grains", "uuid": "1fa1e0f9-6410-4197-8778-debeb274e6d4", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "integers" ] }, { "slug": "isogram", "name": "Isogram", "uuid": "e5338be9-6f51-4448-9b10-20de7b1338b9", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "conditionals", "loops", "parsing", "strings" ] }, { "slug": "leap", "name": "Leap", "uuid": "639e59b6-84aa-4f13-9718-537606703c43", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "conditionals", "integers" ] }, { "slug": "nucleotide-count", "name": "Nucleotide Count", "uuid": "62bd648a-e959-4ec4-8a5f-09e08fa0b2c8", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "conditionals", "exception_handling", "integers", "maps", "parsing", "searching", "strings" ] }, { "slug": "protein-translation", "name": "Protein Translation", "uuid": "368ba5ef-8c54-4016-93df-3a7d3b136243", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "algorithms", "lists", "conditionals", "loops", "strings" ] }, { "slug": "rna-transcription", "name": "RNA Transcription", "uuid": "9772c916-c619-445c-834d-af7dbf1ad2d9", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "loops", "maps", "strings" ] }, { "slug": "sum-of-multiples", "name": "Sum of Multiples", "uuid": "d3f960e5-cf19-4308-a1bc-897777f62689", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "arrays", "conditionals", "integers", "loops", "math" ] }, { "slug": "triangle", "name": "Triangle", "uuid": "e282536b-267f-490c-a453-758135051a54", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "conditionals", "exception_handling", "integers", "recursion" ] }, { "slug": "two-fer", "name": "Two Fer", "uuid": "40f85461-c256-4b96-8d5b-0509f42fab17", "practices": [], "prerequisites": [], "difficulty": 2, "topics": [ "conditionals", "strings" ] }, { "slug": "acronym", "name": "Acronym", "uuid": "d8288e46-2e8c-42e4-8e14-20b1efd0f574", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "loops", "parsing", "searching", "strings" ] }, { "slug": "allergies", "name": "Allergies", "uuid": "a826af04-b7f3-426e-9bce-42375d0d928b", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "booleans", "conditionals", "enumerations", "integers", "lists", "loops" ] }, { "slug": "anagram", "name": "Anagram", "uuid": "f754e1cc-cb88-4776-ab11-3e6ae8362d5a", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "arrays", "conditionals", "equality", "lists", "loops", "strings" ] }, { "slug": "armstrong-numbers", "name": "Armstrong Numbers", "uuid": "3905dff6-7835-44ff-a8c9-7f4d184ab714", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "algorithms", "loops", "math" ] }, { "slug": "binary-search", "name": "Binary Search", "uuid": "c8815b6c-19b8-4f4d-9be4-6717e933591a", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "arrays", "generics", "recursion", "searching" ] }, { "slug": "clock", "name": "Clock", "uuid": "1dcefdea-5447-4622-a064-079aad781398", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "equality", "integers", "logic", "object_oriented_programming", "strings", "time" ] }, { "slug": "crypto-square", "name": "Crypto Square", "uuid": "2928cf06-dab8-4522-a6d8-b2a15d7d356b", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "strings", "text_formatting", "transforming" ] }, { "slug": "difference-of-squares", "name": "Difference of Squares", "uuid": "d54a68fc-02dd-45ee-8c6f-3efb781ed0d2", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "integers", "loops", "math" ] }, { "slug": "dnd-character", "name": "D&D Character", "uuid": "a550dafa-bcec-448c-a7dd-af0ebd4e1070", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "integers", "randomness" ] }, { "slug": "flatten-array", "name": "Flatten Array", "uuid": "c67907b6-0d8b-4b12-9c41-6069845952a3", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "stacks", "strings" ] }, { "slug": "gigasecond", "name": "Gigasecond", "uuid": "1eb4c9d3-0085-4ca3-b1bb-9a20b88a1e7f", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "dates", "integers", "time" ] }, { "slug": "hamming", "name": "Hamming", "uuid": "7151ff23-ebc6-43d7-86b6-81cf0dd45309", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "integers", "loops", "strings" ] }, { "slug": "pangram", "name": "Pangram", "uuid": "0e9ca09d-c32e-4fed-930f-1b7c10b67dc2", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "pattern_matching", "regular_expressions", "strings" ] }, { "slug": "perfect-numbers", "name": "Perfect Numbers", "uuid": "ad7c8fd8-acf0-40d0-8a30-d959c4b0252a", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "enumerations", "exception_handling", "filtering", "integers", "math" ] }, { "slug": "phone-number", "name": "Phone Number", "uuid": "2c8c1c16-bbb8-49e5-a248-f7a473c2bc86", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "conditionals", "pattern_matching", "regular_expressions", "strings" ] }, { "slug": "prime-factors", "name": "Prime Factors", "uuid": "0e92ba19-2727-4a5e-be38-e88878322c53", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "arrays", "conditionals", "integers", "lists", "loops", "math" ] }, { "slug": "raindrops", "name": "Raindrops", "uuid": "93ee76ba-d19f-4c72-b011-676f40dcda5e", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "conditionals", "integers", "strings" ] }, { "slug": "resistor-color", "name": "Resistor Color", "uuid": "9d62b45c-1acf-4ae6-b990-73e5bc2b5893", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "lists" ] }, { "slug": "resistor-color-duo", "name": "Resistor Color Duo", "uuid": "84bdc53f-aa1f-4ddf-9c5d-95b03cfff72d", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "lists" ] }, { "slug": "resistor-color-trio", "name": "Resistor Color Trio", "uuid": "ae4df67d-c848-42e6-9fd7-d3cec83c1691", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "math", "type_conversion", "lists" ] }, { "slug": "rotational-cipher", "name": "Rotational Cipher", "uuid": "7c24087a-ca61-48d3-9cb9-c3fde2edba86", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "cryptography", "integers", "strings" ] }, { "slug": "run-length-encoding", "name": "Run-Length Encoding", "uuid": "483b5124-b5b2-4bb0-aa69-b04e3ea6aeb6", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "loops", "regular_expressions", "strings", "transforming", "type_conversion" ] }, { "slug": "scale-generator", "name": "Scale Generator", "uuid": "dfa35a61-07da-4317-8c25-0c630e551d8c", "practices": [], "prerequisites": [], "difficulty": 3, "status": "deprecated", "topics": [ "lists", "strings" ] }, { "slug": "scrabble-score", "name": "Scrabble Score", "uuid": "4d8a68eb-eee9-4c51-97b8-57f3b69f5970", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "games", "loops", "pattern_matching", "strings", "transforming" ] }, { "slug": "secret-handshake", "name": "Secret Handshake", "uuid": "feee3ee9-81d5-4a4f-ad98-e1ecf21757ed", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "bitwise_operations", "conditionals", "cryptography", "enumerations", "integers", "loops", "transforming" ] }, { "slug": "series", "name": "Series", "uuid": "9caa5fd9-a774-4d4c-951d-053a4f3f2726", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "conditionals", "lists", "loops", "strings", "type_conversion" ] }, { "slug": "space-age", "name": "Space Age", "uuid": "a91ce7e9-9a2a-44de-b10c-cc1be63df2a1", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "conditionals", "floating_point_numbers" ] }, { "slug": "sublist", "name": "Sublist", "uuid": "ebfdf40a-1fde-4c88-aa93-95e3190f5261", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "enumerations", "generics", "lists", "loops", "searching" ] }, { "slug": "word-count", "name": "Word Count", "uuid": "3b8b77ef-da2d-499d-9513-8fe771e86b3e", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "conditionals", "integers", "loops", "maps", "strings" ] }, { "slug": "yacht", "name": "Yacht", "uuid": "2702ffe9-26c3-4f68-86dc-2993dfa2de91", "practices": [], "prerequisites": [], "difficulty": 3, "topics": [ "enums", "functional_programming", "lists", "pattern_matching" ] }, { "slug": "affine-cipher", "name": "Affine Cipher", "uuid": "94fdd990-101b-4daf-8692-75085e6563f2", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "cryptography", "security", "strings" ] }, { "slug": "all-your-base", "name": "All Your Base", "uuid": "19d00436-f26a-47ad-b13e-128181dc09f3", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "arrays", "conditionals", "exception_handling", "integers", "loops", "math" ] }, { "slug": "atbash-cipher", "name": "Atbash Cipher", "uuid": "b325401a-c8f0-49da-9f1a-a83318e780c9", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "cryptography", "security", "strings" ] }, { "slug": "diamond", "name": "Diamond", "uuid": "03c71e34-ecaf-47a4-9854-48600e1bf0d4", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "arrays", "lists", "loops", "strings", "text_formatting" ] }, { "slug": "grade-school", "name": "Grade School", "uuid": "62eb71dd-18ba-427f-a27a-86e993b4055a", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "conditionals", "lists", "maps", "sorting", "strings" ] }, { "slug": "isbn-verifier", "name": "ISBN Verifier", "uuid": "400d8014-9f75-43da-8a1c-93d95d91f4d2", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "integers", "loops", "strings" ] }, { "slug": "kindergarten-garden", "name": "Kindergarten Garden", "uuid": "1603e77a-0fbc-43ed-8200-b86a4219af8d", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "arrays", "enumerations", "lists", "logic", "loops", "pattern_recognition", "strings" ] }, { "slug": "largest-series-product", "name": "Largest Series Product", "uuid": "aa11e242-77b9-4ba7-97a2-d9b36e454a9d", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "integers", "loops", "math", "strings", "type_conversion" ] }, { "slug": "luhn", "name": "Luhn", "uuid": "3cf8a650-6a25-416e-a0af-036f41c11cca", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "algorithms", "booleans", "loops", "strings", "type_conversion" ] }, { "slug": "matrix", "name": "Matrix", "uuid": "46ab876c-cde2-4fa7-8970-b250ad8ccf74", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "loops", "strings", "pattern_matching", "type_conversion", "transforming" ] }, { "slug": "nth-prime", "name": "Nth Prime", "uuid": "6e2bbe8d-b6ab-4675-9c31-5b437cefd0c4", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "arrays", "exception_handling", "integers", "lists", "loops", "math" ] }, { "slug": "robot-simulator", "name": "Robot Simulator", "uuid": "6e3b294b-16a3-4ebb-a78b-4bf7f6b96736", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "classes", "enumerations", "logic", "loops" ] }, { "slug": "roman-numerals", "name": "Roman Numerals", "uuid": "da466ad5-6837-47d8-af39-2c0563d35a3c", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "integers", "logic", "loops", "maps", "strings" ] }, { "slug": "saddle-points", "name": "Saddle Points", "uuid": "371901d4-0728-4abd-8374-1905d7d70329", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "arrays", "conditionals", "exception_handling", "integers", "loops" ] }, { "slug": "sieve", "name": "Sieve", "uuid": "87ca4323-8a19-4529-962d-0f2ee63ebb2f", "practices": [], "prerequisites": [], "difficulty": 4, "topics": [ "algorithms", "integers", "lists", "loops", "math" ] }, { "slug": "binary-search-tree", "name": "Binary Search Tree", "uuid": "12a9dd9f-28ed-4159-baf3-d28654cb8fa7", "practices": [], "prerequisites": [], "difficulty": 5, "topics": [ "arrays", "generics", "recursion", "searching" ] }, { "slug": "circular-buffer", "name": "Circular Buffer", "uuid": "e32c0edd-367c-4b66-b677-35e518d6831f", "practices": [], "prerequisites": [ "generics" ], "difficulty": 5 }, { "slug": "custom-set", "name": "Custom Set", "uuid": "10b6cca2-6c36-4017-9464-32aa11c59f85", "practices": [], "prerequisites": [], "difficulty": 5, "topics": [ "object_oriented_programming", "sets", "varargs" ] }, { "slug": "knapsack", "name": "Knapsack", "uuid": "1c2e8e65-1d1f-43ce-a626-70769f8bae5f", "practices": [], "prerequisites": [ "arrays", "loops", "lists", "conditionals" ], "difficulty": 5, "topics": [ "algorithms", "logic" ] }, { "slug": "matching-brackets", "name": "Matching Brackets", "uuid": "cbbbd7db-224f-45ca-a108-4dc6bc98e4a0", "practices": [], "prerequisites": [], "difficulty": 5, "topics": [ "stacks", "strings" ] }, { "slug": "meetup", "name": "Meetup", "uuid": "d617987e-64b8-4c21-89a9-66a932c4668d", "practices": [], "prerequisites": [], "difficulty": 5, "topics": [ "conditionals", "dates", "enumerations", "loops" ] }, { "slug": "pascals-triangle", "name": "Pascal's Triangle", "uuid": "67db30e4-b4d8-4224-b0f8-19a00af40387", "practices": [], "prerequisites": [], "difficulty": 5, "topics": [ "algorithms", "arrays", "exception_handling", "integers", "math", "matrices" ] }, { "slug": "pig-latin", "name": "Pig Latin", "uuid": "cb2ce8e5-f143-4423-a3bc-959f4222c186", "practices": [], "prerequisites": [], "difficulty": 5, "topics": [ "arrays", "lists", "strings", "transforming" ] }, { "slug": "robot-name", "name": "Robot Name", "uuid": "ce475b23-5dfc-4049-90c5-0c387926686f", "practices": [], "prerequisites": [], "difficulty": 5, "topics": [ "pattern_matching", "randomness", "regular_expressions", "strings", "text_formatting" ] }, { "slug": "spiral-matrix", "name": "Spiral Matrix", "uuid": "e3407da5-0524-4565-b724-9778bba1033f", "practices": [], "prerequisites": [], "difficulty": 5, "topics": [ "arrays", "integers", "loops", "matrices" ] }, { "slug": "transpose", "name": "Transpose", "uuid": "045de074-eeb3-499e-9cf4-65b75d9988fc", "practices": [], "prerequisites": [], "difficulty": 5, "topics": [ "lists", "loops", "maps", "strings" ] }, { "slug": "bank-account", "name": "Bank Account", "uuid": "12e1d685-32be-4b2c-a40b-c68e5b60de1d", "practices": [], "prerequisites": [], "difficulty": 6, "topics": [ "concurrency", "exception_handling", "integers" ] }, { "slug": "beer-song", "name": "Beer Song", "uuid": "34f0e7d0-29df-44e5-a7a7-4a12584af62e", "practices": [], "prerequisites": [], "difficulty": 6, "status": "deprecated", "topics": [ "conditionals", "loops", "strings", "text_formatting", "variables" ] }, { "slug": "bottle-song", "name": "Bottle Song", "uuid": "3e82fc4b-0863-43c1-86b5-70dce3c78711", "practices": [], "prerequisites": [], "difficulty": 6, "topics": [ "conditionals", "loops", "strings", "text_formatting", "variables" ] }, { "slug": "bowling", "name": "Bowling", "uuid": "ae084405-48d7-43ea-9bc5-6c4ebae4c1ef", "practices": [], "prerequisites": [ "for-loops", "arrays" ], "difficulty": 6 }, { "slug": "flower-field", "name": "Flower Field", "uuid": "2bc77dfb-0e27-4beb-b8a1-20bed83ab6b7", "practices": [], "prerequisites": [], "difficulty": 6, "topics": [ "conditionals", "games", "integers", "lists", "matrices", "strings" ] }, { "slug": "linked-list", "name": "Linked List", "uuid": "fc977979-c8a4-44b6-a685-c8a32bd12bc3", "practices": [], "prerequisites": [], "difficulty": 6, "topics": [ "algorithms", "generics", "lists" ] }, { "slug": "minesweeper", "name": "Minesweeper", "uuid": "8eb6f225-fa3d-4a33-b476-2cae45053c82", "practices": [], "prerequisites": [], "difficulty": 6, "topics": [ "conditionals", "games", "integers", "lists", "matrices", "strings" ], "status": "deprecated" }, { "slug": "rail-fence-cipher", "name": "Rail Fence Cipher", "uuid": "49e730fb-7031-4de9-9bfd-b86564f20d8a", "practices": [], "prerequisites": [], "difficulty": 6, "topics": [ "cryptography", "algorithms", "strings", "transforming" ] }, { "slug": "say", "name": "Say", "uuid": "5607dae5-13aa-4cd4-8b4c-d270516182d7", "practices": [], "prerequisites": [], "difficulty": 6, "topics": [ "strings", "transforming" ] }, { "slug": "wordy", "name": "Wordy", "uuid": "3c7a3c6b-8dc7-4e5a-ba72-e1a4bffb0bc4", "practices": [], "prerequisites": [], "difficulty": 6, "topics": [ "loops", "pattern_matching", "strings", "recursion" ] }, { "slug": "dominoes", "name": "Dominoes", "uuid": "c52c4b61-dca2-4b73-87b6-b4f2f63d9fdb", "practices": [], "prerequisites": [], "difficulty": 7, "topics": [ "algorithms", "exception_handling", "games", "lists" ] }, { "slug": "change", "name": "Change", "uuid": "0d69c1cd-f190-4b3b-8472-bf78c02acbc5", "practices": [], "prerequisites": [], "difficulty": 8, "topics": [ "algorithms", "exception_handling", "integers", "lists" ] }, { "slug": "complex-numbers", "name": "Complex Numbers", "uuid": "83dec96f-9cdf-4b9b-abc4-cbd2066d919a", "practices": [], "prerequisites": [], "difficulty": 8, "topics": [ "floating_point_numbers", "math" ] }, { "slug": "diffie-hellman", "name": "Diffie-Hellman", "uuid": "33d64c7c-292e-4221-aed8-ac411a9d490d", "practices": [], "prerequisites": [], "difficulty": 8, "topics": [ "cryptography", "randomness", "algorithms", "integers" ] }, { "slug": "forth", "name": "Forth", "uuid": "81d48ea4-0e88-45f2-839f-fe13e2059e92", "practices": [], "prerequisites": [], "difficulty": 8, "topics": [ "pattern_matching", "integers" ] }, { "slug": "list-ops", "name": "List Ops", "uuid": "34f1d5bf-f31f-415e-9905-4d48e6205d28", "practices": [], "prerequisites": [], "difficulty": 8, "topics": [ "filtering", "functional_programming", "generics", "lists", "loops" ] }, { "slug": "simple-cipher", "name": "Simple Cipher", "uuid": "e23b06de-bd91-482f-9783-b0334b75b489", "practices": [], "prerequisites": [], "difficulty": 8, "topics": [ "cryptography", "exception_handling", "randomness", "security", "strings" ] }, { "slug": "zebra-puzzle", "name": "Zebra Puzzle", "uuid": "fe876a9b-2991-4624-a6fe-4311cb78f068", "practices": [], "prerequisites": [], "difficulty": 9, "topics": [ "algorithms", "arrays", "conditionals", "games" ] }, { "slug": "react", "name": "React", "uuid": "240788cd-afa5-4fd6-8df0-a158239c0610", "practices": [], "prerequisites": [], "difficulty": 10, "topics": [ "generics", "functional_programming", "classes", "reactive_programming" ] } ] }, "concepts": [ { "uuid": "72e47dcb-dccf-44a5-ab91-8773c2aec5bd", "slug": "basics", "name": "Basics" }, { "uuid": "53e0b729-810e-4042-9477-8c8d05a7b302", "slug": "booleans", "name": "Booleans" }, { "uuid": "157bbe3b-e4f5-41f7-8e0e-e2f57d526617", "slug": "strings", "name": "Strings" }, { "uuid": "168827c0-4867-449a-ad22-611c87314c48", "slug": "conditionals", "name": "Conditionals" }, { "uuid": "660e1acd-3072-4bbc-ae44-bbc204da5eab", "slug": "chars", "name": "Chars" }, { "uuid": "98809a4c-ca3e-4504-b723-aff13bfae850", "slug": "nullability", "name": "Nullability" }, { "uuid": "1050abed-4271-4519-a44c-a0ca121c7de2", "slug": "bitwise-operations", "name": "Bitwise Operations" } ], "key_features": [ { "title": "Pragmatic", "content": "Kotlin is trying hard to be a modern language with great tooling support.", "icon": "powerful" }, { "title": "Statically Typed", "content": "Strong type-safety and null-safety features for building robust software.", "icon": "immutable" }, { "title": "Multi-Paradigm", "content": "Kotlin support both functional and mainstream OOP programming principles.", "icon": "multi-paradigm" }, { "title": "Platform Independent", "content": "Develop for Android, iOS, JVM, Node.js, browser and many native targets.", "icon": "cross-platform" }, { "title": "Garbage collected", "content": "Kotlin (as a modern generic-purpose language) does memory management for you.", "icon": "garbage-collected" }, { "title": "Open-Source", "content": "Kotlin is fully open-source. Submit patches or suggest language improvements.", "icon": "community" } ], "tags": [ "execution_mode/compiled", "paradigm/functional", "paradigm/imperative", "paradigm/object_oriented", "platform/android", "platform/linux", "platform/mac", "platform/web", "platform/windows", "runtime/jvm", "typing/static", "typing/strong", "used_for/backends", "used_for/cross_platform_development", "used_for/games", "used_for/mobile" ] } ================================================ FILE: docs/ABOUT.md ================================================ # About Kotlin was designed and developed by JetBrains, the company behind IntelliJ. It is a language that runs on the JVM which can target versions 6+ (including the [Android platform](https://blog.jetbrains.com/kotlin/2017/05/kotlin-on-android-now-official/)). JetBrains wanted to use a statically typed language which can remove Java boilerplate code, provide modern functional paradigms, and had seamless two-way Java interoperability with their existing codebase. The JVM already had alternate languages like Groovy and Scala but neither fit the bill with their desired criteria, so they built Kotlin. Kotlin syntax is similar to Scala and Swift but pulls in the best-of-breed features from other languages such as C# and Groovy. Kotlin took a pragmatic approach at features included in the language by only providing functionality that has been proven to be useful for developers. With this decision they implemented a subset of features of Scala with the intent that it will provide more maintainable code with an easier learning curve for developers looking for a "better Java". JetBrains has a dedicated team of developers working on Kotlin with the codebase available on [Github](https://github.com/JetBrains/kotlin). ================================================ FILE: docs/INSTALLATION.md ================================================ # Installing Kotlin In addition to the exercism CLI and your favorite text editor, practicing with Exercism exercises in Kotlin requires * the **Java Development Kit** (JDK) — Kotlin compiles to Java bytecodes; you need to install the JDK which includes both a Java Runtime *and* development tools (most notably, the Java compiler); and * **Gradle** — a build tool specifically for JVM-based projects and supports Kotlin. Choose your operating system: * [Windows](#h-windows) * [macOS](#h-macos) * [Linux](#h-linux) ... or ... * if you prefer to not use a package manager, you can [install manually](#h-install-manually). Optionally, you can also use a [Java IDE](#h-java-ides). ---- ## Windows Open an administrative command prompt. (If you need assistance opening an administrative prompt, see [open an elevated prompt in Windows 8+](http://www.howtogeek.com/194041/how-to-open-the-command-prompt-as-administrator-in-windows-8.1/) (or [Windows 7](http://www.howtogeek.com/howto/windows-vista/run-a-command-as-administrator-from-the-windows-vista-run-box/)). 1. If you have not installed Chocolatey, do so now: ```batchfile C:\Windows\system32> @powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin ``` 2. Install the JDK: ```batchfile C:\Windows\system32> choco install openjdk11 ... C:\Windows\system32> refreshenv ... ``` We recommend closing the administrative command prompt and opening a new command prompt -- you do not require administrator privileges to practice Exercism exercises. You now are ready to get started with the Kotlin track of Exercism! To get started, see "[Running the Tests](https://exercism.org/docs/tracks/kotlin/tests)". ---- ## macOS Below are instructions for install using the most common method - using Homebrew. If you'd rather, you can also [install on macOS without Homebrew](#h-installing-on-macos-without-homebrew). ### Installing 1. If you haven't installed [Homebrew](http://brew.sh), yet, do so now: ```sh $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" ``` 2. Tap the [Homebrew Cask](https://caskroom.github.io/) — this allows us to install pre-built binaries like the JDK. ``` $ brew tap adoptopenjdk/openjdk ``` 3. Install the JDK: ``` $ brew install --cask adoptopenjdk11 ``` You now are ready to get started with the Kotlin track of Exercism! To get started, see "[Running the Tests](https://exercism.org/docs/tracks/kotlin/tests)". ---- ## Linux Below are instructions for install using the package manager of your distro. If you'd rather, you can also [install on Linux without a package manager](#h-installing-on-linux-without-a-package-manager). * [Debian](#h-debian) * [Other Linux distributions](#h-other-linux-distributions) ### Debian If you are using Debian or its derivatives (like Ubuntu or Linux Mint), use APT: *(verified on: Ubuntu 14, 16 and 18)* 1. Install the JDK: ```sh $ sudo apt-get update $ sudo apt-get install software-properties-common $ sudo add-apt-repository ppa:openjdk-r/ppa $ sudo apt-get update $ sudo apt-get install openjdk-11-jdk ``` You now are ready to get started with the Kotlin track of Exercism! To get started, see "[Running the Tests](https://exercism.org/docs/tracks/kotlin/tests)". ---- ### Other Linux distributions There are a lot of ways to install Jdk 11, but one of the easiest ways is to use SDKMAN, which lets you install OpenJdk11 with ease. Use the following steps: 1. Install SDKMAN: ```sh $ curl -s "https://get.sdkman.io" | bash ``` (if that doesn't work, take a look at the instructions found here: https://sdkman.io/install ) 1. Install openjdk11: ``` $ sdk install java 11.0.2-open ``` You now are ready to get started with the Kotlin track of Exercism! To get started, see "[Running the Tests](https://exercism.org/docs/tracks/kotlin/tests)". ---- ## Install Manually * [Installing on Windows manually](#h-installing-on-windows-manually) * [Installing on macOS without Homebrew](#h-installing-on-macos-without-homebrew) * [Installing on Linux without a package manager](#h-installing-on-linux-without-a-package-manager) ---- ### Installing on Windows manually *NOTE: these instructions are intended for experienced Windows users. If you don't already know how to set environment variables or feel comfortable managing the directory structure, we highly recommend you use the Chocolatey-based install, [above](#h-windows).* 1. Install the JDK: 1. Download "**OpenJDK 11 (LTS)**" from [AdoptOpenJDK](https://adoptopenjdk.net/releases.html?variant=openjdk11#x64_win) (choose **"Install JDK"**). - Run the installer, using all the defaults. You now are ready to get started with the Kotlin track of Exercism! To get started, see "[Running the Tests](https://exercism.org/docs/tracks/kotlin/tests)". ---- ### Installing on macOS without Homebrew *NOTE: these instructions are intended for experienced macOS users. Unless you specifically do not want to use a package manager, we highly recommend using the Homebrew-based installation instructions, [above](#h-macos).* 1. Install the JDK: 1. Download "**OpenJDK 11 (LTS)**" from [AdoptOpenJDK](https://adoptopenjdk.net/releases.html?variant=openjdk11#x64_mac) (choose **"Install JDK"**). 2. Run the installer, using all the defaults. You now are ready to get started with the Kotlin track of Exercism! To get started, see "[Running the Tests](https://exercism.org/docs/tracks/kotlin/tests)". ---- ### Installing on Linux without a package manager *NOTE: these instructions are intended for experienced Linux users. Unless you specifically do not want to use a package manager, we highly recommend using the the installation instructions, [above](#h-linux).* 1. Install the JDK: 1. Choose your distribution and download "**OpenJDK 11 (LTS)**" from [AdoptOpenJDK](https://adoptopenjdk.net/releases.html?variant=openjdk11) (choose **"Install JDK"**). 2. Run the installer, using all the defaults. You now are ready to get started with the Kotlin track of Exercism! To get started, see "[Running the Tests](https://exercism.org/docs/tracks/kotlin/tests)". ---- ## Java IDEs There are many Java IDEs available. The three most popular are: * [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) (download the "Community" edition) - from the authors of Kotlin, this IDE provides the best support for the language. - [Eclipse](https://www.eclipse.org/downloads/) - [NetBeans](https://netbeans.org/downloads/) (download the "Java SE" bundle) and there are [others](https://en.wikibooks.org/wiki/Java_Programming/Java_IDEs). ================================================ FILE: docs/LEARNING.md ================================================ # Recommended learning resources * [Get started with Kotlin](https://kotlinlang.org/docs/getting-started.html) * [Kotlin Documentation](https://kotlinlang.org/docs/home.html) * [Kotlin Idioms](https://kotlinlang.org/docs/idioms.html) * [Kotlin Tutorial Videos](https://kotlinlang.org/docs/videos.html) * [Kotlin examples](https://play.kotlinlang.org/byExample/overview) * [Kotlin on Stack Overflow](https://stackoverflow.com/questions/tagged/kotlin) ================================================ FILE: docs/RESOURCES.md ================================================ # Recommended resources * [Kotlin Documentation](https://kotlinlang.org/docs/reference/) * [Kotlin Forums](https://discuss.kotlinlang.org/) * [Kotlin Slack Channel](http://kotlinlang.slack.com/): [get invite here](http://slack.kotlinlang.org/) * [Stack Overflow](https://stackoverflow.com/questions/tagged/kotlin) * [Reddit Channel](https://www.reddit.com/r/kotlin) * [X (formerly Twitter)](https://x.com/kotlin) ================================================ FILE: docs/SNIPPET.txt ================================================ fun getGreeting(): String { return "Hello, World!" } ================================================ FILE: docs/TESTS.md ================================================ # Tests ## Running the Tests 1. Get an exercise: ```bash $ exercism download -track=kotlin --exercise=hello-world ``` 2. Change directory into the exercise: ```bash $ cd ``` 3. Run the tests: ```bash $ ./gradlew test ``` On most exercises, only the first test is run by default. The other tests are annotated with `@Ignore` to skip them. As you solve each test, remove the `@Ignore` from the next one to progress. This is common practice in test-driven development (or TDD for short). It is used to ensure that you are working on one problem at a time. --- Good luck! Have fun! If you get stuck at any point, feel free to reach out for help on the [forum](https://exercism.org/r/forum) or our `#get-help` channel on our [Discord server](https://exercism.org/r/discord). ================================================ FILE: docs/config.json ================================================ { "docs": [ { "uuid": "91fa3615-3f2d-44fe-a060-93dac297583c", "slug": "installation", "path": "docs/INSTALLATION.md", "title": "Installing Kotlin locally", "blurb": "Learn how to install Kotlin locally to solve Exercism's exercises on your own machine" }, { "uuid": "015670c8-aded-4ba5-9824-454e928b8d37", "slug": "learning", "path": "docs/LEARNING.md", "title": "How to learn Kotlin", "blurb": "An overview of how to get started from scratch with Kotlin" }, { "uuid": "f2a23a48-b160-4925-98c6-8844ab63b931", "slug": "tests", "path": "docs/TESTS.md", "title": "Testing on the Kotlin track", "blurb": "Learn how to test your Kotlin exercises on Exercism" }, { "uuid": "336b6d0a-43a1-44d4-b1ac-0320aed1baa7", "slug": "resources", "path": "docs/RESOURCES.md", "title": "Useful Kotlin resources", "blurb": "A collection of useful resources to help you master Kotlin" } ] } ================================================ FILE: exercises/build.gradle.kts ================================================ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { kotlin("jvm") } project(":practice").subprojects { afterEvaluate { configurations { create("starterSourceCompile").extendsFrom(getByName("implementation")) create("starterSourceRuntime").extendsFrom(getByName("runtimeOnly")) create("exerciseTestsCompile").extendsFrom(getByName("testImplementation")) create("exerciseTestsRuntime").extendsFrom(getByName("testRuntimeOnly")) } kotlin { sourceSets { main { kotlin.setSrcDirs(listOf(file(".meta/src/reference/kotlin"))) } test { kotlin.setSrcDirs(listOf("build/gen/test/kotlin")) } val starterSource by creating { kotlin.setSrcDirs(listOf("src/main/kotlin")) } val exerciseTests by creating { kotlin.setSrcDirs(listOf("src/test/kotlin")) } } } tasks { val copyTestsFilteringIgnores by creating(Copy::class) { from("src/test/kotlin") into("build/gen/test/kotlin") filter { line -> if (line.contains("@Ignore")) "" else line } } compileKotlin { doFirst { println(" (source = ${source.asPath})") } } compileTestKotlin { dependsOn(copyTestsFilteringIgnores) doFirst { println(" (test source = ${source.asPath})") } } /*val compileStarterSourceKotlin by existing(KotlinCompile::class) { println(" (source = ${source.asPath})") }*/ } } } ================================================ FILE: exercises/concept/annalyns-infiltration/.docs/hints.md ================================================ # Hints ## General - There are three [boolean operators][reference] to work with boolean values. - Multiple operators can be combined in a single expression. ## 1. Check if a fast attack can be made - The [boolean operators][reference] can also be applied to boolean parameters. [reference]: https://kotlinlang.org/docs/reference/basic-types.html#booleans ================================================ FILE: exercises/concept/annalyns-infiltration/.docs/instructions.md ================================================ # Instructions In this exercise, you'll be implementing the quest logic for a new RPG game a friend is developing. The game's main character is Annalyn, a brave girl with a fierce and loyal pet dog. Unfortunately, disaster strikes, as her best friend was kidnapped while searching for berries in the forest. Annalyn will try to find and free her best friend, optionally taking her dog with her on this quest. After some time spent following her best friend's trail, she finds the camp in which her best friend is imprisoned. It turns out there are two kidnappers: a mighty knight and a cunning archer. Having found the kidnappers, Annalyn considers which of the following actions she can engage in: - Fast attack: a fast attack can be made if the knight is sleeping, as it takes time for him to get his armor on, so he will be vulnerable. - Spy: the group can be spied upon if at least one of them is awake. Otherwise, spying is a waste of time. - Signal prisoner: the prisoner can be signalled using bird sounds if the prisoner is awake and the archer is sleeping, as archers are trained in bird signaling so they could intercept the message. - _Free prisoner_: Annalyn can try sneaking into the camp to free the prisoner. This is a risky thing to do and can only succeed in one of two ways: - If Annalyn has her pet dog with her she can rescue the prisoner if the archer is asleep. The knight is scared of the dog and the archer will not have time to get ready before Annalyn and the prisoner can escape. - If Annalyn does not have her dog then she and the prisoner must be very sneaky! Annalyn can free the prisoner if the prisoner is awake and the knight and archer are both sleeping, but if the prisoner is sleeping they can't be rescued: the prisoner would be startled by Annalyn's sudden appearance and wake up the knight and archer. You have four tasks: to implement the logic for determining if the above actions are available based on the state of the three characters found in the forest and whether Annalyn's pet dog is present or not. ## 1. Check if a fast attack can be made Implement the `canFastAttack()` method that takes a boolean value that indicates if the knight is awake. This method returns `true` if a fast attack can be made based on the state of the knight. Otherwise, returns `false`: ```kotlin val knightIsAwake = true canFastAttack(knightIsAwake) // => false ``` ## 2. Check if the group can be spied upon Implement the `canSpy()` method that takes three boolean values, indicating if the knight, archer and the prisoner, respectively, are awake. The method returns `true` if the group can be spied upon, based on the state of the three characters. Otherwise, returns `false`: ```kotlin val knightIsAwake = false val archerIsAwake = true val prisonerIsAwake = false canSpy(knightIsAwake, archerIsAwake, prisonerIsAwake) // => true ``` ## 3. Check if the prisoner can be signalled Implement the `canSignalPrisoner()` method that takes two boolean values, indicating if the archer and the prisoner, respectively, are awake. The method returns `true` if the prisoner can be signalled, based on the state of the two characters. Otherwise, returns `false`: ```kotlin val archerIsAwake = false val prisonerIsAwake = true canSignalPrisoner(archerIsAwake, prisonerIsAwake) // => true ``` ## 4. Check if the prisoner can be freed Implement the `canFreePrisoner()` method that takes four boolean values. The first three parameters indicate if the knight, archer and the prisoner, respectively, are awake. The last parameter indicates if Annalyn's pet dog is present. The method returns `true` if the prisoner can be freed based on the state of the three characters and Annalyn's pet dog presence. Otherwise, it returns `false`: ```kotlin val knightIsAwake = false val archerIsAwake = true val prisonerIsAwake = false val petDogIsPresent = false canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent) // => false ``` ================================================ FILE: exercises/concept/annalyns-infiltration/.docs/introduction.md ================================================ # Introduction Booleans in Kotlin are represented by the `Boolean` type, which values can be either `true` or `false`. Kotlin supports three built-in [boolean operators][reference]: `!` (negation aka NOT), `&&` (lazy conjunction aka AND), and `||` (lazy disjunction aka OR). The `&&` and `||` operators use _short-circuit evaluation_, which means that the right-hand side of the operator is only evaluated when needed. ================================================ FILE: exercises/concept/annalyns-infiltration/.meta/config.json ================================================ { "authors": [ "dector" ], "files": { "solution": [ "src/main/kotlin/AnnalynsInfiltration.kt" ], "test": [ "src/test/kotlin/AnnalynsInfiltrationTest.kt" ], "exemplar": [ ".meta/src/reference/kotlin/AnnalynsInfiltration.kt" ] }, "forked_from": [ "fsharp/annalyns-infiltration" ], "blurb": "Learn about booleans while helping Annalyn rescue her friend." } ================================================ FILE: exercises/concept/annalyns-infiltration/.meta/design.md ================================================ # Design ## Learning objectives - Know of the existence of the `Boolean` type and its two values. - Know about boolean operators and how to build logical expressions with them. - Know of the boolean operator precedence rules. ## Out of scope - Pattern matching on booleans. ## Concepts - `booleans`: know of the existence of the `Boolean` type and its two values; know about boolean operators and how to build logical expressions with them; know of the boolean operator precedence rules. ## Prerequisites This exercise's prerequisites Concepts are: - `basics`: know how to define methods. ================================================ FILE: exercises/concept/annalyns-infiltration/.meta/src/reference/kotlin/AnnalynsInfiltration.kt ================================================ fun canFastAttack(knightIsAwake: Boolean): Boolean = !knightIsAwake fun canSpy( knightIsAwake: Boolean, archerIsAwake: Boolean, prisonerIsAwake: Boolean ): Boolean = knightIsAwake || archerIsAwake || prisonerIsAwake fun canSignalPrisoner(archerIsAwake: Boolean, prisonerIsAwake: Boolean): Boolean = !archerIsAwake && prisonerIsAwake fun canFreePrisoner( knightIsAwake: Boolean, archerIsAwake: Boolean, prisonerIsAwake: Boolean, petDogIsPresent: Boolean ): Boolean = !knightIsAwake && !archerIsAwake && prisonerIsAwake || !archerIsAwake && petDogIsPresent ================================================ FILE: exercises/concept/annalyns-infiltration/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/concept/annalyns-infiltration/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/concept/annalyns-infiltration/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/concept/annalyns-infiltration/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/concept/annalyns-infiltration/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/concept/annalyns-infiltration/src/main/kotlin/AnnalynsInfiltration.kt ================================================ fun canFastAttack(knightIsAwake: Boolean): Boolean { TODO("Please implement the canFastAttack() method") } fun canSpy( knightIsAwake: Boolean, archerIsAwake: Boolean, prisonerIsAwake: Boolean ): Boolean { TODO("Please implement the canSpy() method") } fun canSignalPrisoner(archerIsAwake: Boolean, prisonerIsAwake: Boolean): Boolean { TODO("Please implement the canSignalPrisoner() method") } fun canFreePrisoner( knightIsAwake: Boolean, archerIsAwake: Boolean, prisonerIsAwake: Boolean, petDogIsPresent: Boolean ): Boolean { TODO("Please implement the canFreePrisoner() method") } ================================================ FILE: exercises/concept/annalyns-infiltration/src/test/kotlin/AnnalynsInfiltrationTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertFalse import kotlin.test.assertTrue class AnnalynsInfiltrationTest { @Test fun `Cannot execute fast attack if knight is awake`() { val knightIsAwake = true assertFalse(canFastAttack(knightIsAwake)) } @Test fun `Can execute fast attack if knight is sleeping`() { val knightIsAwake = false assertTrue(canFastAttack(knightIsAwake)) } @Test fun `Cannot spy if everyone is sleeping`() { val knightIsAwake = false val archerIsAwake = false val prisonerIsAwake = false assertFalse(canSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)) } @Test fun `Can spy if everyone but knight is sleeping`() { val knightIsAwake = true val archerIsAwake = false val prisonerIsAwake = false assertTrue(canSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)) } @Test fun `Can spy if everyone but archer is sleeping`() { val knightIsAwake = false val archerIsAwake = true val prisonerIsAwake = false assertTrue(canSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)) } @Test fun `Can spy if everyone but prisoner is sleeping`() { val knightIsAwake = false val archerIsAwake = false val prisonerIsAwake = true assertTrue(canSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)) } @Test fun `Can spy if only knight is sleeping`() { val knightIsAwake = false val archerIsAwake = true val prisonerIsAwake = true assertTrue(canSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)) } @Test fun `Can spy if only archer is sleeping`() { val knightIsAwake = true val archerIsAwake = false val prisonerIsAwake = true assertTrue(canSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)) } @Test fun `Can spy if only prisoner is sleeping`() { val knightIsAwake = true val archerIsAwake = true val prisonerIsAwake = false assertTrue(canSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)) } @Test fun `Can spy if everyone is awake`() { val knightIsAwake = true val archerIsAwake = true val prisonerIsAwake = true assertTrue(canSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)) } @Test fun `Can signal prisoner ifarcher is sleeping and prisoner is awake`() { val archerIsAwake = false val prisonerIsAwake = true assertTrue(canSignalPrisoner(archerIsAwake, prisonerIsAwake)) } @Test fun `Cannot signal prisoner ifarcher is awake and prisoner is sleeping`() { val archerIsAwake = true val prisonerIsAwake = false assertFalse(canSignalPrisoner(archerIsAwake, prisonerIsAwake)) } @Test fun `Cannot signal prisoner ifarcher and prisoner are both sleeping`() { val archerIsAwake = false val prisonerIsAwake = false assertFalse(canSignalPrisoner(archerIsAwake, prisonerIsAwake)) } @Test fun `Cannot signal prisoner ifarcher and prisoner are both awake`() { val archerIsAwake = true val prisonerIsAwake = true assertFalse(canSignalPrisoner(archerIsAwake, prisonerIsAwake)) } @Test fun `Cannot release prisoner if everyone is awake and pet dog is present`() { val knightIsAwake = true val archerIsAwake = true val prisonerIsAwake = true val petDogIsPresent = true assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if everyone is awake and pet dog is absent`() { val knightIsAwake = true val archerIsAwake = true val prisonerIsAwake = true val petDogIsPresent = false assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Can release prisoner if everyone is asleep and pet dog is present`() { val knightIsAwake = false val archerIsAwake = false val prisonerIsAwake = false val petDogIsPresent = true assertTrue(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if everyone is asleep and pet dog is absent`() { val knightIsAwake = false val archerIsAwake = false val prisonerIsAwake = false val petDogIsPresent = false assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Can release prisoner if only prisoner is awake and pet dog is present`() { val knightIsAwake = false val archerIsAwake = false val prisonerIsAwake = true val petDogIsPresent = true assertTrue(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Can release prisoner if only prisoner is awake and pet dog is absent`() { val knightIsAwake = false val archerIsAwake = false val prisonerIsAwake = true val petDogIsPresent = false assertTrue(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if only archer is awake and pet dog is present`() { val knightIsAwake = false val archerIsAwake = true val prisonerIsAwake = false val petDogIsPresent = true assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if only archer is awake and pet dog is absent`() { val knightIsAwake = false val archerIsAwake = true val prisonerIsAwake = false val petDogIsPresent = false assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Can release prisoner if only knight is awake and pet dog is present`() { val knightIsAwake = true val archerIsAwake = false val prisonerIsAwake = false val petDogIsPresent = true assertTrue(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if only knight is awake and pet dog is absent`() { val knightIsAwake = true val archerIsAwake = false val prisonerIsAwake = false val petDogIsPresent = false assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if only knight is asleep and pet dog is present`() { val knightIsAwake = false val archerIsAwake = true val prisonerIsAwake = true val petDogIsPresent = true assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if only knight is asleep and pet dog is absent`() { val knightIsAwake = false val archerIsAwake = true val prisonerIsAwake = true val petDogIsPresent = false assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Can release prisoner if only archer is asleep and pet dog is present`() { val knightIsAwake = true val archerIsAwake = false val prisonerIsAwake = true val petDogIsPresent = true assertTrue(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if only archer is asleep and pet dog is absent`() { val knightIsAwake = true val archerIsAwake = false val prisonerIsAwake = true val petDogIsPresent = false assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if only prisoner is asleep and pet dog is present`() { val knightIsAwake = true val archerIsAwake = true val prisonerIsAwake = false val petDogIsPresent = true assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } @Test fun `Cannot release prisoner if only prisoner is asleep and pet dog is absent`() { val knightIsAwake = true val archerIsAwake = true val prisonerIsAwake = false val petDogIsPresent = false assertFalse(canFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)) } } ================================================ FILE: exercises/concept/log-levels/.docs/hints.md ================================================ # Hints ## General - Kotlin provides many [functions][ref-strings] for working with Strings. Be sure to check out the `Members & Extensions` tab! ## 1. Get message from a log line - There is a [function][ref-string-substringAfter] to extract the part of a `String` after a given delimiter. - Removing whitespace from a `String` is explored in [Remove All Whitespaces from a String in Kotlin][tutorial-trim-white-space]. ## 2. Get log level from a log line - There is also a [function][ref-string-substringBefore] to extract part of a `String` _before_ a given delimiter. - There is a [way][ref-string-lowercase] to change a `String` to lowercase. ## 3. Reformat a log line - [String templates][docs-string-template] can be done with a [multiline string][docs-string-multiline]. [docs-string-multiline]: https://kotlinlang.org/docs/strings.html#multiline-strings [docs-string-template]: https://kotlinlang.org/docs/strings.html#string-templates [ref-strings]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/ [ref-string-indexOf]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/#-537588047%2FFunctions%2F-1430298843 [ref-string-lowercase]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/#-648004414%2FFunctions%2F-956074838 [ref-string-substringAfter]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/#1564391517%2FFunctions%2F-1430298843 [tutorial-search-text-in-string]: https://javarevisited.blogspot.com/2016/10/how-to-check-if-string-contains-another-substring-in-java-indexof-example.html [tutorial-trim-white-space]: https://www.baeldung.com/kotlin/string-remove-whitespace ================================================ FILE: exercises/concept/log-levels/.docs/instructions.md ================================================ # Instructions In this exercise you'll be processing log-liners. Each log line is a string formatted as follows: "[]: *". ## 1. Get the message from a log line Implement the `LogLevels.message()` function to return the message from a log line, with the leading and trailing whitespaces removed. ## 2. Get the log level from a log line Implement the `LogLevels.logLevel()` function to return the log level from a log line in lower case. ## 3. Reformat a log line Implement the `LogLevels.reformat()` method that takes a log line and a location string and reformats into a message containing two lines. The first line is formatted as `@:`, where: * `` is the log level in lower case (as from 2. Get the log level from a log line). * `` is the location given as the second parameter. The second line contains exactly two spaces, followed by the log message (as from 1. Get the message from a log line): ```kotlin reformat("[TRACE]: Start of function", 2, 8) // => "trace@208: Start of function" ``` ================================================ FILE: exercises/concept/log-levels/.docs/introduction.md ================================================ # Introduction A [`string`][ref-string] in Kotlin is an immutable sequence of Unicode characters. [`Immutable`][wiki-immutable] means that any operation on a string must return a new string: the original string can never change. [`Unicode`][wiki-unicode] means that most of the world's writing systems can be represented, but (in contrast to older languages such as C) there is no 1:1 mapping between characters and bytes. A string is usually surrounded by double-quotes `" "`. Some characters need escaping: `\'`, `\\`, plus the usual non-printing characters such as `\t` (tab) and `\n` (newline). ```kotlin val s = "Escape apostrophe \' and backslash \\." // Escape apostrophe ' and backslash \. ``` Multi-line strings are surrounded by 3 double-quotes, and can contain arbitrary text (no need for escaping). ```kotlin val multi = """I'm a multi-line string with special characters \ \t """ //I'm a // multi-line // string with special characters \ \t ``` Use [trimIndent][trimIndent-doc] to remove the common indenting from the lines. This is useful for formatting the string: ```kotlin val multi = """ I'm a multi-line string""".trimIndent() //I'm a // multi-line //string ``` Alternatively, [trimMargin][trimMargin-doc] lets you specify a delimiter. Each line in the `String` then begins after the delimiter. The delimiter defaults to `|`, but you can specify a different delimiter as a parameter. For example: ```kotlin val multi = """ |I'm a | multi-line |string""".trimMargin() //I'm a // multi-line //string val multi2 = """ start>I'm a start> multi-line start>string""".trimMargin("start>") //I'm a // multi-line //string ``` Strings can be concatenated with `+`, but this is best limited to short and simple cases. There are other and often better options. ## String templates This refers to what some other languages call "interpolation". If a string contains a dollar sign `$`, followed by an identifier, or contains braces (`{expression}`) surrounding an expression, those are substituted by respectively the value or the result of the expression. ```kotlin val x = 42 val st = "x is $x, x squared is {x * x}" // x is 42, x squared is 1764 ``` The braces `{ }` are needed around expressions when parsing would otherwise be ambiguous. In general, use of string templates is a more efficient and idiomatic way to combine strings than using `+`. ## String functions Kotlin provides _many_ [`functions`][ref-string-functions] to manipulate strings. Mostly, these are [`extensions functions`][ref-extensions] rather than members of the `String` class, though this has little effect on how we use them. ~~~~exercism/note Kotlin's rather complex [documentation][ref-string-functions] pages hide extension functions in the default view. Be sure to click `Members & Extensions` to expand this section. [ref-string-functions]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/ ~~~~ The following examples show just a small selection of what is available: ```kotlin val str = "Hello World!" str.length // => 12 (a property, not a function) str.elementAt(6) // => W str.elementAtOrNull(20) // => null (index out of range) str.substring(6, 11) // => "World" str.substringAfter(" ") // => "World!" str.lowercase() // => "hello world!" str.uppercase() // => "HELLO WORLD!" str.startsWith("Hel") // => true str.endsWith("xyz") // => false str.indexOf("0") // => 4 str.toCharArray() // => [H, e, l, l, o, , W, o, r, l, d, !] "42".toInt() + 1 // => 43 (parsing; see also toFloat) "Howdy! ".trim() // => "Howdy" ``` [ref-string]: https://kotlinlang.org/docs/strings.html [wiki-immutable]: https://en.wikipedia.org/wiki/Immutable_object [wiki-unicode]: https://en.wikipedia.org/wiki/Unicode [ref-stringbuilder]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-string-builder/ [ref-extensions]: https://kotlinlang.org/docs/extensions.html#extensions.md [ref-string-functions]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/ [trimIndent-doc]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/trim-indent.html [trimMargin-doc]: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/trim-margin.html ================================================ FILE: exercises/concept/log-levels/.meta/config.json ================================================ { "authors": [ "kahgoh" ], "files": { "solution": [ "src/main/kotlin/LogLevels.kt" ], "test": [ "src/test/kotlin/LogLevelsTest.kt" ], "exemplar": [ ".meta/src/reference/kotlin/LogLevels.kt" ] }, "blurb": "Learn about strings by processing logs." } ================================================ FILE: exercises/concept/log-levels/.meta/src/reference/kotlin/LogLevels.kt ================================================ fun message(logLine : String) : String { return logLine.substringAfter(":").trim() } fun logLevel(logLine : String) : String { return logLine.substringBefore(":").removeSurrounding("[", "]").lowercase() } fun reformat(logLine : String, location : String) : String { return """ |${logLevel(logLine)}@$location: | ${message(logLine)} """.trimMargin() } ================================================ FILE: exercises/concept/log-levels/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/concept/log-levels/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/concept/log-levels/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/concept/log-levels/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/concept/log-levels/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/concept/log-levels/src/main/kotlin/LogLevels.kt ================================================ fun message(logLine : String) : String { TODO("Please implement the message() function") } fun logLevel(logLine : String) : String { TODO("Please implement the logLevel() function") } fun reformat(logLine : String, location : String) : String { TODO("Please implement the reformat() method") } ================================================ FILE: exercises/concept/log-levels/src/test/kotlin/LogLevelsTest.kt ================================================ import kotlin.test.Test import kotlin.test.assertEquals class LogLevelsTest { @Test fun `error message`() { assertEquals("Stack overflow", message("[ERROR]: Stack overflow")) } @Test fun `warning message`() { assertEquals("Disk almost full", message("[WARNING]: Disk almost full")) } @Test fun `info message`() { assertEquals("File info", message("[INFO]: File info")) } @Test fun `warning message with leading and trailing whitespace`() { val logLine = """[WARNING]: Timezone not set """ assertEquals("Timezone not set", message(logLine)) } @Test fun `error log level`() { assertEquals("error", logLevel("[ERROR]: Stack overflow")) } @Test fun `warning log level`() { assertEquals("warning", logLevel("[WARNING]: Disk almost full")) } @Test fun `info log level`() { assertEquals("info", logLevel("[INFO]: File info")) } @Test fun `warning log level with leading and trailing whitespace`() { val logLine = """[WARNING]: Timezone not set """ assertEquals("warning", logLevel(logLine)) } @Test fun `reformat error log line`() { val expected = """ |error@code: | Segmentation fault """.trimMargin() assertEquals(expected, reformat("[ERROR]: Segmentation fault", "code")) } @Test fun `reformat warn log line`() { val expected = """ |warn@CPU: | High temperature """.trimMargin() assertEquals(expected, reformat("[WARN]: High temperature", "CPU")) } @Test fun `reformat info log line`() { val expected = """ |info@disk: | Disk defragmented """.trimMargin() assertEquals(expected, reformat("[INFO]: Disk defragmented", "disk")) } @Test fun `reformat a log line with multiple whitespace`() { val expected = """ |notice@shell: | Entered bad input too many times! | | This incident will be reported! """.trimMargin() val logLine = """ |[NOTICE]: Entered bad input too many times! | | This incident will be reported! """.trimMargin() assertEquals(expected, reformat(logLine, "shell")) } } ================================================ FILE: exercises/concept/lucians-luscious-lasagna/.docs/hints.md ================================================ # Hints ## General - An [integer (`Int`) value][numbers] can be defined as one or more consecutive digits. - Use variables to give nice and readable names for your values. Remember that code readability is much more important than amount of code lines. ## 1. Calculate remaining baking time in minutes - You need to define a [function][functions] with a single parameter. - You need to assign a [default value][function-defaults] for the parameter. - You have to explicitly return an integer value from a method. - The method's parameter is an [integer][numbers]. - You need to use the mathematical operator for subtraction (`-`) to subtract values. ## 2. Calculate the preparation time in minutes - You need to define a [function][functions] with a single parameter. - You have to explicitly return an integer value from a method. - The method's parameter is an [integer][numbers]. - You need to use the mathematical operator for addition (`+`) to add values. ## 3. Calculate the elapsed time in minutes - You need to define a [function][functions] with a two parameters. - You need to assign a [default value][function-defaults] for the second parameter. - You have to explicitly return an integer value from a method. - The method's parameter is an [integer][numbers]. - You need to use the mathematical operator for addition (`+`) to add values. - You need to call already implemented functions. [numbers]: https://kotlinlang.org/docs/reference/basic-types.html#numbers [functions]: https://kotlinlang.org/docs/reference/functions.html#function-declarations [function-defaults]: https://kotlinlang.org/docs/reference/functions.html#default-arguments ================================================ FILE: exercises/concept/lucians-luscious-lasagna/.docs/instructions.md ================================================ # Instructions The owner of your local pizza place has asked you to help her to calculate cooking times for different pizzas. In this exercise you're going to write few functions to calculate that. You have three tasks. ## 1. Calculate remaining baking time in minutes Define and implement the `remainingMinutesInOven()` function that will count how many more minutes you need to keep the pizza in the oven. The function should accept one **optional** parameter (with default value) for the amount of minutes that passed since you've started baking pizza. If the parameter is missing - assume that you've just put pizza into the oven and **0 (zero)** minutes passed already. For simplicity - let's assume that all types of pizzas require exactly 40 minutes in the oven to be ready. ```kotlin remainingMinutesInOven() // => 40 remainingMinutesInOven(10) // => 30 ``` ## 2. Calculate the preparation time in minutes Before baking the pizza, you need to prepare the dough, roll it out and put toppings onto it. Define and implement the `preparationTimeInMinutes()` function that will count how many minutes it will take to prepare pizza before putting it into the oven. The function should accept one **required** parameter (`numberOfIngredientTypes`) for the number of topping ingredient types that will be used. Assume that you need 5 minutes to make and roll out dough and 2 minutes for using **each** kind of topping. ```kotlin preparationTimeInMinutes(0) // => 5 preparationTimeInMinutes(1) // => 7 ``` ## 3. Calculate the elapsed time in minutes Define and implement the `elapsedCookingTimeInMinutes()` function that will count how many minutes it will take to prepare, bake and serve the pizza. Use the functions from the previous steps while making the calculations. The function should accept two parameters. The first one is **required** and is the number of topping ingredient types. The second one is **optional** and is the serving time in minutes (assume that is 0 if not provided). ```kotlin elapsedCookingTimeInMinutes(1) // => 47 elapsedCookingTimeInMinutes(2, 3) // => 52 ``` ================================================ FILE: exercises/concept/lucians-luscious-lasagna/.docs/introduction.md ================================================ # Introduction Kotlin is a **statically typed** programming language developed by JetBrains. This means that the type of variables is defined at compile-time. ## Variables Similarly to other statically-typed programming languages, the type of each variable should be defined at compile time. You can avoid explicit type declarations where they can be inferred by the compiler from their context. Kotlin has immutable (`val`) and mutable (`var`) variables. The value of an immutable variable can't be changed after it's initial value is assigned. Most of the time you will use this type of variable. ```kotlin val robotName = "HAL-9000" userId = "T-1000" // This will not compile ``` A mutable variable's value can be changed one or more times: ```kotlin var index = 12 print(index) // 12 index = 100 print(index) // 100 ``` Semicolons in Kotlin are optional, except for a few special cases that will be covered later. ## Functions Functions in Kotlin are defined with the `fun` keyword and are _first-class citizens_ (not related to OOP). It means that you can declare (so-called `top-level functions`) them right in files (e.g. in Java you can define methods only in classes, not in files): ```kotlin // This is content of the Hello.kt file fun hello() {} ``` Functions can receive arguments. Each argument has a name and a type. Unlike variables, the type of arguments can't be inferred. Functions can have zero or more arguments: ```kotlin fun hello() {} fun hello(name: String) {} fun hello(name: String, age: Int) {} ``` Kotlin functions might or might not return a value: ```kotlin fun min(a: Int, b: Int): Int fun countBonuses(user: User): Bonuses fun run() {} ``` To return a value from a function, the `return` keyword is used: ```kotlin fun getName(): String { return "Alice" } ``` Functions can have parameters with default values. These values will be used if they are omitted where function is invoked: ```kotlin fun ping(host: String = "localhost") { println("PING --> $host") } ping("exercism.io") // PING --> exercism.io ping() // PING --> localhost ``` ## Comments Use `//` to define single-line comment: ```kotlin foo() // Everything after `//` will be ignored by compiler // I will be ignored too ``` or `/*` and `*/` to define multi-line comments: ```kotlin /* This this an example for a multiline comment */ ``` ================================================ FILE: exercises/concept/lucians-luscious-lasagna/.meta/config.json ================================================ { "authors": [ "dector" ], "files": { "solution": [ "src/main/kotlin/LuciansLusciousLasagna.kt" ], "test": [ "src/test/kotlin/LuciansLusciousLasagnaTests.kt" ], "exemplar": [ ".meta/src/reference/kotlin/LuciansLusciousLasagna.kt" ] }, "forked_from": [ "fsharp/lucians-luscious-lasagna" ], "blurb": "Learn about the basics of Kotlin by following a lasagna recipe." } ================================================ FILE: exercises/concept/lucians-luscious-lasagna/.meta/design.md ================================================ # Design ## Goal This exercise should teach bare minimum to help students understand Kotlin programs. ## Learning objectives - Know what a variable is. - Know how to define a variable. - Know the difference between immutable and mutable variable. - Know how to update a variable. - Know how to define a method. - Know how to return a value from a method. - Know how to call a method. - Know about basic types: Int, Unit. - Know how to define single and multiline comments. ## Out of scope - More advanced data types: String, Float/Double/Number, Nothing etc. - Calling function with named parameters. - Inline functions. - Classes/Objects. - Packages ## Concepts The Concepts this exercise unlocks are: - `basics`: know what a variable is; know how to define a variable; know the difference between immutable and mutable variable; know how to update a variable; know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about basic types: Int, Unit; know how to define single and multiline comments. ## Prerequisites _none_ ## Resources to refer to [Kotlin docs](https://kotlinlang.org/docs/reference/basic-syntax.html) ## Representer ## Analyzer ================================================ FILE: exercises/concept/lucians-luscious-lasagna/.meta/src/reference/kotlin/LuciansLusciousLasagna.kt ================================================ fun remainingMinutesInOven(actualMinutesInOven: Int = 0): Int { val cookingTime = 40 return cookingTime - actualMinutesInOven } fun preparationTimeInMinutes(numberOfIngredientTypes: Int): Int { return 5 + numberOfIngredientTypes * 2 } fun elapsedCookingTimeInMinutes(numberOfIngredientTypes: Int, servingTimeInMinutes: Int = 0): Int { val preparationTime = preparationTimeInMinutes(numberOfIngredientTypes) val backingTime = remainingMinutesInOven() return preparationTime + backingTime + servingTimeInMinutes } ================================================ FILE: exercises/concept/lucians-luscious-lasagna/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/concept/lucians-luscious-lasagna/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/concept/lucians-luscious-lasagna/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/concept/lucians-luscious-lasagna/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/concept/lucians-luscious-lasagna/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/concept/lucians-luscious-lasagna/src/main/kotlin/LuciansLusciousLasagna.kt ================================================ // TODO: define `remainingMinutesInOven()`. Use named variable to store expected time in oven. // TODO: define `preparationTimeInMinutes()`. // TODO: define `elapsedCookingTimeInMinutes()`. ================================================ FILE: exercises/concept/lucians-luscious-lasagna/src/test/kotlin/LuciansLusciousLasagnaTests.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertFalse import kotlin.test.assertTrue class LuciansLusciousLasagnaTests { @Test fun `test`() { } } ================================================ FILE: exercises/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/gradle.properties ================================================ kotlin.incremental=false org.gradle.parallel=true ================================================ FILE: exercises/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/accumulate/.docs/instructions.md ================================================ # Instructions Implement the `accumulate` operation, which, given a collection and an operation to perform on each element of the collection, returns a new collection containing the result of applying that operation to each element of the input collection. Given the collection of numbers: - 1, 2, 3, 4, 5 And the operation: - square a number (`x => x * x`) Your code should be able to produce the collection of squares: - 1, 4, 9, 16, 25 Check out the test suite to see the expected function signature. ## Restrictions Keep your hands off that collect/map/fmap/whatchamacallit functionality provided by your standard library! Solve this one yourself using other basic tools instead. ================================================ FILE: exercises/practice/accumulate/.meta/config.json ================================================ { "blurb": "Implement the `accumulate` operation, which, given a collection and an operation to perform on each element of the collection, returns a new collection containing the result of applying that operation to each element of the input collection.", "authors": ["sdavids13"], "contributors": [ "dector", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": ["src/main/kotlin/Accumulate.kt"], "test": ["src/test/kotlin/AccumulateTest.kt"], "example": [".meta/src/reference/kotlin/Accumulate.kt"] }, "source": "Conversation with James Edward Gray II", "source_url": "https://twitter.com/jeg2" } ================================================ FILE: exercises/practice/accumulate/.meta/src/reference/kotlin/Accumulate.kt ================================================ object Accumulate { fun accumulate(collection: List, function: (T) -> R): List { val retVal = mutableListOf() for(item in collection) { retVal.add(function.invoke(item)) } return retVal } } ================================================ FILE: exercises/practice/accumulate/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/accumulate/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/accumulate/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/accumulate/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/accumulate/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/accumulate/src/main/kotlin/Accumulate.kt ================================================ object Accumulate { fun accumulate(collection: List, converter: (Any) -> Any): List { TODO("Change the function signature and implement it to complete the task") } } ================================================ FILE: exercises/practice/accumulate/src/test/kotlin/AccumulateTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class AccumulateTest { @Test fun emptyAccumulateProducesEmptyAccumulation() { val input = listOf() val expectedOutput = listOf() assertEquals(expectedOutput, Accumulate.accumulate(input, { x -> x * x })) } @Ignore @Test fun accumulateSquares() { val input = listOf(1, 2, 3) val expectedOutput = listOf(1, 4, 9) assertEquals(expectedOutput, Accumulate.accumulate(input, { x -> x * x })) } @Ignore @Test fun accumulateUpperCases() { val input = listOf("hello", "world") val expectedOutput = listOf("HELLO", "WORLD") assertEquals(expectedOutput, Accumulate.accumulate(input, { it.toUpperCase() })) } @Ignore @Test fun accumulateReversedStrings() { val input = "the quick brown fox etc".split(" ") val expectedOutput = "eht kciuq nworb xof cte".split(" ") assertEquals(expectedOutput, Accumulate.accumulate(input, { it.reversed() })) } @Ignore @Test fun accumulateWithinAccumulate() { val input1 = listOf("a", "b", "c") val input2 = listOf("1", "2", "3") val expectedOutput = listOf("a1 a2 a3", "b1 b2 b3", "c1 c2 c3") assertEquals(expectedOutput, Accumulate.accumulate(input1, { c -> Accumulate.accumulate(input2, { d -> c + d }).joinToString(" ") } )) } @Ignore @Test fun accumulateToDifferentType() { val input = listOf(1, 2, 3) val expectedOutput = listOf("1", "2", "3") assertEquals(expectedOutput, Accumulate.accumulate(input, { it.toString() })) } } ================================================ FILE: exercises/practice/acronym/.docs/instructions.md ================================================ # Instructions Convert a phrase to its acronym. Techies love their TLA (Three Letter Acronyms)! Help generate some jargon by writing a program that converts a long name like Portable Network Graphics to its acronym (PNG). Punctuation is handled as follows: hyphens are word separators (like whitespace); all other punctuation can be removed from the input. For example: | Input | Output | | ------------------------- | ------ | | As Soon As Possible | ASAP | | Liquid-crystal display | LCD | | Thank George It's Friday! | TGIF | ================================================ FILE: exercises/practice/acronym/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "beatbrot", "dector", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Acronym.kt" ], "test": [ "src/test/kotlin/AcronymTest.kt" ], "example": [ ".meta/src/reference/kotlin/Acronym.kt" ] }, "blurb": "Convert a long phrase to its acronym.", "source": "Julien Vanier", "source_url": "https://github.com/monkbroc" } ================================================ FILE: exercises/practice/acronym/.meta/src/reference/kotlin/Acronym.kt ================================================ object Acronym { fun generate(phrase: String) = Regex("[A-Z]+[a-z]*|[a-z]+") .findAll(phrase.replace("'", "")) .map { it.value.first().uppercaseChar() } .joinToString("") } ================================================ FILE: exercises/practice/acronym/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [1e22cceb-c5e4-4562-9afe-aef07ad1eaf4] description = "basic" [79ae3889-a5c0-4b01-baf0-232d31180c08] description = "lowercase words" [ec7000a7-3931-4a17-890e-33ca2073a548] description = "punctuation" [32dd261c-0c92-469a-9c5c-b192e94a63b0] description = "all caps word" [ae2ac9fa-a606-4d05-8244-3bcc4659c1d4] description = "punctuation without whitespace" [0e4b1e7c-1a6d-48fb-81a7-bf65eb9e69f9] description = "very long abbreviation" [6a078f49-c68d-4b7b-89af-33a1a98c28cc] description = "consecutive delimiters" [5118b4b1-4572-434c-8d57-5b762e57973e] description = "apostrophes" [adc12eab-ec2d-414f-b48c-66a4fc06cdef] description = "underscore emphasis" ================================================ FILE: exercises/practice/acronym/.meta/version ================================================ 1.7.0 ================================================ FILE: exercises/practice/acronym/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/acronym/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/acronym/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/acronym/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/acronym/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/acronym/src/main/kotlin/Acronym.kt ================================================ object Acronym { fun generate(phrase: String) : String { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/acronym/src/test/kotlin/AcronymTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class AcronymTest { @Test fun `capitalized words`() = assertAcronymEquals( "Portable Network Graphics", "PNG") @Ignore @Test fun `lowercase word in the middle`() = assertAcronymEquals( "Ruby on Rails", "ROR") @Ignore @Test fun `punctuation is ignored`() = assertAcronymEquals( "First In, First Out", "FIFO") @Ignore @Test fun `uppercased word at the start`() = assertAcronymEquals( "GNU Image Manipulation Program", "GIMP") @Ignore @Test fun `hyphen is ignored`() = assertAcronymEquals( "Complementary metal-oxide semiconductor", "CMOS") @Ignore @Test fun `lots of words`() = assertAcronymEquals( "Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me", "ROTFLSHTMDCOALM") @Ignore @Test fun `consecutive delimiters`() = assertAcronymEquals( "Something - I made up from thin air", "SIMUFTA") @Ignore @Test fun `apostrophe is ignored`() = assertAcronymEquals( "Halley's Comet", "HC") @Ignore @Test fun `underscore emphasis is ignored`() = assertAcronymEquals( "The Road _Not_ Taken", "TRNT") } private fun assertAcronymEquals(origin: String, acronym: String) = assertEquals(acronym, Acronym.generate(origin)) ================================================ FILE: exercises/practice/affine-cipher/.docs/instructions.md ================================================ # Instructions Create an implementation of the affine cipher, an ancient encryption system created in the Middle East. The affine cipher is a type of monoalphabetic substitution cipher. Each character is mapped to its numeric equivalent, encrypted with a mathematical function and then converted to the letter relating to its new numeric value. Although all monoalphabetic ciphers are weak, the affine cipher is much stronger than the Atbash cipher, because it has many more keys. [//]: # " monoalphabetic as spelled by Merriam-Webster, compare to polyalphabetic " ## Encryption The encryption function is: ```text E(x) = (ai + b) mod m ``` Where: - `i` is the letter's index from `0` to the length of the alphabet - 1. - `m` is the length of the alphabet. For the Latin alphabet `m` is `26`. - `a` and `b` are integers which make up the encryption key. Values `a` and `m` must be _coprime_ (or, _relatively prime_) for automatic decryption to succeed, i.e., they have number `1` as their only common factor (more information can be found in the [Wikipedia article about coprime integers][coprime-integers]). In case `a` is not coprime to `m`, your program should indicate that this is an error. Otherwise it should encrypt or decrypt with the provided key. For the purpose of this exercise, digits are valid input but they are not encrypted. Spaces and punctuation characters are excluded. Ciphertext is written out in groups of fixed length separated by space, the traditional group size being `5` letters. This is to make it harder to guess encrypted text based on word boundaries. ## Decryption The decryption function is: ```text D(y) = (a^-1)(y - b) mod m ``` Where: - `y` is the numeric value of an encrypted letter, i.e., `y = E(x)` - it is important to note that `a^-1` is the modular multiplicative inverse (MMI) of `a mod m` - the modular multiplicative inverse only exists if `a` and `m` are coprime. The MMI of `a` is `x` such that the remainder after dividing `ax` by `m` is `1`: ```text ax mod m = 1 ``` More information regarding how to find a Modular Multiplicative Inverse and what it means can be found in the [related Wikipedia article][mmi]. ## General Examples - Encrypting `"test"` gives `"ybty"` with the key `a = 5`, `b = 7` - Decrypting `"ybty"` gives `"test"` with the key `a = 5`, `b = 7` - Decrypting `"ybty"` gives `"lqul"` with the wrong key `a = 11`, `b = 7` - Decrypting `"kqlfd jzvgy tpaet icdhm rtwly kqlon ubstx"` gives `"thequickbrownfoxjumpsoverthelazydog"` with the key `a = 19`, `b = 13` - Encrypting `"test"` with the key `a = 18`, `b = 13` is an error because `18` and `26` are not coprime ## Example of finding a Modular Multiplicative Inverse (MMI) Finding MMI for `a = 15`: - `(15 * x) mod 26 = 1` - `(15 * 7) mod 26 = 1`, ie. `105 mod 26 = 1` - `7` is the MMI of `15 mod 26` [mmi]: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse [coprime-integers]: https://en.wikipedia.org/wiki/Coprime_integers ================================================ FILE: exercises/practice/affine-cipher/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/AffineCipher.kt" ], "test": [ "src/test/kotlin/AffineCipherTest.kt" ], "example": [ ".meta/src/reference/kotlin/AffineCipher.kt" ] }, "blurb": "Create an implementation of the Affine cipher, an ancient encryption algorithm from the Middle East.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Affine_cipher" } ================================================ FILE: exercises/practice/affine-cipher/.meta/src/reference/kotlin/AffineCipher.kt ================================================ object AffineCipher { /** Number of characters in the alphabet (a-z). */ private const val ALPHABET_SIZE = 26 /** Number of space separated groups in the encoded text. */ private const val GROUP_SIZE = 5 fun encode(cipheredMessage: String, a: Int, b: Int): String { return translate(cipheredMessage, a, b, encode = true) .windowed(GROUP_SIZE, GROUP_SIZE, true) .joinToString(" ") } fun decode(cipheredMessage: String, a: Int, b: Int): String { return translate(cipheredMessage, a, b, encode = false) } private fun modularMultiplicativeInverse(a: Int): Int = (1..ALPHABET_SIZE) .firstOrNull { ((a * it) % ALPHABET_SIZE) == 1 } ?: 1 private fun translate(text: String, a: Int, b: Int, encode: Boolean): String { val inv = modularMultiplicativeInverse(a) require(inv != 1) { "Key A and alphabet size must be coprime!" } return text .lowercase() .mapNotNull { c -> when { c.isDigit() -> c c.isLetter() -> (c - 'a') // the characters alphabetical position, not its ASCII value .let { if (encode) (a * it + b) else (inv * (it - b)) } // the main algorithm .let { 'a' + (it % ALPHABET_SIZE) } // map number to character .let { if (it < 'a') (it + ALPHABET_SIZE) else it } // adjust for negative values else -> null // spaces and the like are ignored } } .joinToString("") } } ================================================ FILE: exercises/practice/affine-cipher/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [2ee1d9af-1c43-416c-b41b-cefd7d4d2b2a] description = "encode -> encode yes" [785bade9-e98b-4d4f-a5b0-087ba3d7de4b] description = "encode -> encode no" [2854851c-48fb-40d8-9bf6-8f192ed25054] description = "encode -> encode OMG" [bc0c1244-b544-49dd-9777-13a770be1bad] description = "encode -> encode O M G" [381a1a20-b74a-46ce-9277-3778625c9e27] description = "encode -> encode mindblowingly" [6686f4e2-753b-47d4-9715-876fdc59029d] description = "encode -> encode numbers" [ae23d5bd-30a8-44b6-afbe-23c8c0c7faa3] description = "encode -> encode deep thought" [c93a8a4d-426c-42ef-9610-76ded6f7ef57] description = "encode -> encode all the letters" [0673638a-4375-40bd-871c-fb6a2c28effb] description = "encode -> encode with a not coprime to m" [3f0ac7e2-ec0e-4a79-949e-95e414953438] description = "decode -> decode exercism" [241ee64d-5a47-4092-a5d7-7939d259e077] description = "decode -> decode a sentence" [33fb16a1-765a-496f-907f-12e644837f5e] description = "decode -> decode numbers" [20bc9dce-c5ec-4db6-a3f1-845c776bcbf7] description = "decode -> decode all the letters" [623e78c0-922d-49c5-8702-227a3e8eaf81] description = "decode -> decode with no spaces in input" [58fd5c2a-1fd9-4563-a80a-71cff200f26f] description = "decode -> decode with too many spaces" [b004626f-c186-4af9-a3f4-58f74cdb86d5] description = "decode -> decode with a not coprime to m" ================================================ FILE: exercises/practice/affine-cipher/.meta/version ================================================ 2.0.0 ================================================ FILE: exercises/practice/affine-cipher/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/affine-cipher/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/affine-cipher/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/affine-cipher/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/affine-cipher/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/affine-cipher/src/main/kotlin/AffineCipher.kt ================================================ object AffineCipher { fun encode(input: String, a: Int, b: Int) { TODO("Implement the function to complete the task") } fun decode(input: String, a: Int, b: Int) { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/affine-cipher/src/test/kotlin/AffineCipherTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith class AffineCipherTest { @Test fun `encode yes`() = assertEquals("xbt", AffineCipher.encode("yes", 5, 7)) @Ignore @Test fun `encode no`() = assertEquals("fu", AffineCipher.encode("no", 15, 18)) @Ignore @Test fun `encode OMG`() = assertEquals("lvz", AffineCipher.encode("OMG", 21, 3)) @Ignore @Test fun `encode O M G`() = assertEquals("hjp", AffineCipher.encode("O M G", 25, 47)) @Ignore @Test fun `encode mindblowingly`() = assertEquals("rzcwa gnxzc dgt", AffineCipher.encode("mindblowingly", 11, 15)) @Ignore @Test fun `encode numbers`() = assertEquals("jqgjc rw123 jqgjc rw", AffineCipher.encode("Testing,1 2 3, testing.", 3, 4)) @Ignore @Test fun `encode deep thought`() = assertEquals("iynia fdqfb ifje", AffineCipher.encode("Truth is fiction.", 5, 17)) @Ignore @Test fun `encode all letters`() = assertEquals("swxtj npvyk lruol iejdc blaxk swxmh qzglf", AffineCipher.encode("The quick brown fox jumps over the lazy dog.", 17, 33)) @Ignore @Test fun `encode with a not coprime to m`() { assertFailsWith("a and m must be coprime.") { AffineCipher.encode("This is a test.", 6, 17) } } @Ignore @Test fun `decode exercism`() = assertEquals("exercism", AffineCipher.decode("tytgn fjr", 3, 7)) @Ignore @Test fun `decode a sentence`() = assertEquals("anobstacleisoftenasteppingstone", AffineCipher.decode("qdwju nqcro muwhn odqun oppmd aunwd o", 19, 16)) @Ignore @Test fun `decode numbers`() = assertEquals("testing123testing", AffineCipher.decode("odpoz ub123 odpoz ub", 25, 7)) @Ignore @Test fun `decode all the letters`() = assertEquals("thequickbrownfoxjumpsoverthelazydog", AffineCipher.decode("swxtj npvyk lruol iejdc blaxk swxmh qzglf", 17, 33)) @Ignore @Test fun `decode with no spaces in input`() = assertEquals("thequickbrownfoxjumpsoverthelazydog", AffineCipher.decode("swxtjnpvyklruoliejdcblaxkswxmhqzglf", 17, 33)) @Ignore @Test fun `decode with too many spaces`() = assertEquals("jollygreengiant", AffineCipher.decode("vszzm cly yd cg qdp", 15, 16)) @Ignore @Test fun `decode with a not coprime to m`() { assertFailsWith("a and m must be coprime.") { AffineCipher.decode("Test", 13, 5) } } } ================================================ FILE: exercises/practice/all-your-base/.docs/instructions.md ================================================ # Instructions Convert a sequence of digits in one base, representing a number, into a sequence of digits in another base, representing the same number. ~~~~exercism/note Try to implement the conversion yourself. Do not use something else to perform the conversion for you. ~~~~ ## About [Positional Notation][positional-notation] In positional notation, a number in base **b** can be understood as a linear combination of powers of **b**. The number 42, _in base 10_, means: `(4 × 10¹) + (2 × 10⁰)` The number 101010, _in base 2_, means: `(1 × 2⁵) + (0 × 2⁴) + (1 × 2³) + (0 × 2²) + (1 × 2¹) + (0 × 2⁰)` The number 1120, _in base 3_, means: `(1 × 3³) + (1 × 3²) + (2 × 3¹) + (0 × 3⁰)` _Yes. Those three numbers above are exactly the same. Congratulations!_ [positional-notation]: https://en.wikipedia.org/wiki/Positional_notation ================================================ FILE: exercises/practice/all-your-base/.docs/introduction.md ================================================ # Introduction You've just been hired as professor of mathematics. Your first week went well, but something is off in your second week. The problem is that every answer given by your students is wrong! Luckily, your math skills have allowed you to identify the problem: the student answers _are_ correct, but they're all in base 2 (binary)! Amazingly, it turns out that each week, the students use a different base. To help you quickly verify the student answers, you'll be building a tool to translate between bases. ================================================ FILE: exercises/practice/all-your-base/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "sophiekoonin", "uzilan" ], "files": { "solution": [ "src/main/kotlin/BaseConverter.kt" ], "test": [ "src/test/kotlin/BaseConverterTest.kt" ], "example": [ ".meta/src/reference/kotlin/BaseConverter.kt" ] }, "blurb": "Convert a number, represented as a sequence of digits in one base, to any other base." } ================================================ FILE: exercises/practice/all-your-base/.meta/src/reference/kotlin/BaseConverter.kt ================================================ import kotlin.math.floor import kotlin.math.pow class BaseConverter(originalBase: Int, originalDigits: IntArray) { companion object { private const val MINIMUM_VALID_BASE = 2 private const val INVALID_BASE_ERROR_MESSAGE = "Bases must be at least 2." } private val numeral: Int init { require(originalBase >= MINIMUM_VALID_BASE) { INVALID_BASE_ERROR_MESSAGE } require(originalDigits.isNotEmpty()) { "You must supply at least one digit." } require(originalDigits.size == 1 || originalDigits[0] != 0) { "Digits may not contain leading zeros." } require(originalDigits.minOrNull()!! >= 0) { "Digits may not be negative." } require(originalDigits.maxOrNull()!! < originalBase) { "All digits must be strictly less than the base." } this.numeral = computeNumeral(originalBase, originalDigits) } fun convertToBase(newBase: Int): IntArray { require(newBase >= MINIMUM_VALID_BASE) { INVALID_BASE_ERROR_MESSAGE } val largestExponent = computeLargestExponentForBase(newBase) val result = IntArray(largestExponent + 1) var remainder = numeral for (currentExponent in largestExponent downTo 0) { val coefficient = floor(remainder / newBase.toDouble().pow(currentExponent.toDouble())).toInt() result[largestExponent - currentExponent] = coefficient remainder -= (coefficient * newBase.toDouble().pow(currentExponent.toDouble())).toInt() } return result } private fun computeNumeral(originalBase: Int, originalDigits: IntArray): Int { val largestExponent = originalDigits.size - 1 val result = (largestExponent downTo 0).sumOf { exponent -> (originalDigits[largestExponent - exponent] * originalBase.toDouble().pow(exponent.toDouble())).toInt() } return result } private fun computeLargestExponentForBase(newBase: Int): Int { var result = 0 while (newBase.toDouble().pow((result + 1).toDouble()) < numeral) { result += 1 } return result } } ================================================ FILE: exercises/practice/all-your-base/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [5ce422f9-7a4b-4f44-ad29-49c67cb32d2c] description = "single bit one to decimal" [0cc3fea8-bb79-46ac-a2ab-5a2c93051033] description = "binary to single decimal" [f12db0f9-0d3d-42c2-b3ba-e38cb375a2b8] description = "single decimal to binary" [2c45cf54-6da3-4748-9733-5a3c765d925b] description = "binary to multiple decimal" [65ddb8b4-8899-4fcc-8618-181b2cf0002d] description = "decimal to binary" [8d418419-02a7-4824-8b7a-352d33c6987e] description = "trinary to hexadecimal" [d3901c80-8190-41b9-bd86-38d988efa956] description = "hexadecimal to trinary" [5d42f85e-21ad-41bd-b9be-a3e8e4258bbf] description = "15-bit integer" [d68788f7-66dd-43f8-a543-f15b6d233f83] description = "empty list" [5e27e8da-5862-4c5f-b2a9-26c0382b6be7] description = "single zero" [2e1c2573-77e4-4b9c-8517-6c56c5bcfdf2] description = "multiple zeros" [3530cd9f-8d6d-43f5-bc6e-b30b1db9629b] description = "leading zeros" [a6b476a1-1901-4f2a-92c4-4d91917ae023] description = "input base is one" [e21a693a-7a69-450b-b393-27415c26a016] description = "input base is zero" [54a23be5-d99e-41cc-88e0-a650ffe5fcc2] description = "input base is negative" [9eccf60c-dcc9-407b-95d8-c37b8be56bb6] description = "negative digit" [232fa4a5-e761-4939-ba0c-ed046cd0676a] description = "invalid positive digit" [14238f95-45da-41dc-95ce-18f860b30ad3] description = "output base is one" [73dac367-da5c-4a37-95fe-c87fad0a4047] description = "output base is zero" [13f81f42-ff53-4e24-89d9-37603a48ebd9] description = "output base is negative" [0e6c895d-8a5d-4868-a345-309d094cfe8d] description = "both bases are negative" ================================================ FILE: exercises/practice/all-your-base/.meta/version ================================================ 2.3.0 ================================================ FILE: exercises/practice/all-your-base/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/all-your-base/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/all-your-base/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/all-your-base/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/all-your-base/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/all-your-base/src/main/kotlin/BaseConverter.kt ================================================ class BaseConverter { // TODO: implement proper constructor to complete the task fun convertToBase(newBase: Int): IntArray { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/all-your-base/src/test/kotlin/BaseConverterTest.kt ================================================ import org.junit.Assert.assertArrayEquals import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException import java.util.* class BaseConverterTest { /* * See https://github.com/junit-team/junit4/wiki/Rules for information on JUnit Rules in general and * ExpectedExceptions in particular. */ @Rule @JvmField var expectedException: ExpectedException = ExpectedException.none() @Test fun testSingleBitOneToDecimal() { val baseConverter = BaseConverter(2, intArrayOf(1)) val expectedDigits = intArrayOf(1) val actualDigits = baseConverter.convertToBase(10) assertArrayEquals( "Expected digits: ${Arrays.toString(expectedDigits)} but found digits: ${Arrays.toString(actualDigits)}", expectedDigits, actualDigits) } @Ignore @Test fun testBinaryToSingleDecimal() { val baseConverter = BaseConverter(2, intArrayOf(1, 0, 1)) val expectedDigits = intArrayOf(5) val actualDigits = baseConverter.convertToBase(10) assertArrayEquals( "Expected digits: ${Arrays.toString(expectedDigits)} but found digits: ${Arrays.toString(actualDigits)}", expectedDigits, actualDigits) } @Ignore @Test fun testSingleDecimalToBinary() { val baseConverter = BaseConverter(10, intArrayOf(5)) val expectedDigits = intArrayOf(1, 0, 1) val actualDigits = baseConverter.convertToBase(2) assertArrayEquals( "Expected digits: ${Arrays.toString(expectedDigits)} but found digits: ${Arrays.toString(actualDigits)}", expectedDigits, actualDigits) } @Ignore @Test fun testBinaryToMultipleDecimal() { val baseConverter = BaseConverter(2, intArrayOf(1, 0, 1, 0, 1, 0)) val expectedDigits = intArrayOf(4, 2) val actualDigits = baseConverter.convertToBase(10) assertArrayEquals( "Expected digits: ${Arrays.toString(expectedDigits)} but found digits: ${Arrays.toString(actualDigits)}", expectedDigits, actualDigits) } @Ignore @Test fun testDecimalToBinary() { val baseConverter = BaseConverter(10, intArrayOf(4, 2)) val expectedDigits = intArrayOf(1, 0, 1, 0, 1, 0) val actualDigits = baseConverter.convertToBase(2) assertArrayEquals( "Expected digits: ${Arrays.toString(expectedDigits)} but found digits: ${Arrays.toString(actualDigits)}", expectedDigits, actualDigits) } @Ignore @Test fun testTrinaryToHexadecimal() { val baseConverter = BaseConverter(3, intArrayOf(1, 1, 2, 0)) val expectedDigits = intArrayOf(2, 10) val actualDigits = baseConverter.convertToBase(16) assertArrayEquals( "Expected digits: ${Arrays.toString(expectedDigits)} but found digits: ${Arrays.toString(actualDigits)}", expectedDigits, actualDigits) } @Ignore @Test fun testHexadecimalToTrinary() { val baseConverter = BaseConverter(16, intArrayOf(2, 10)) val expectedDigits = intArrayOf(1, 1, 2, 0) val actualDigits = baseConverter.convertToBase(3) assertArrayEquals( "Expected digits: ${Arrays.toString(expectedDigits)} but found digits: ${Arrays.toString(actualDigits)}", expectedDigits, actualDigits) } @Ignore @Test fun test15BitInteger() { val baseConverter = BaseConverter(97, intArrayOf(3, 46, 60)) val expectedDigits = intArrayOf(6, 10, 45) val actualDigits = baseConverter.convertToBase(73) assertArrayEquals( "Expected digits: ${Arrays.toString(expectedDigits)} but found digits: ${Arrays.toString(actualDigits)}", expectedDigits, actualDigits) } @Ignore @Test fun testEmptyDigits() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("You must supply at least one digit.") BaseConverter(2, intArrayOf()) } @Ignore @Test fun testSingleZero() { val baseConverter = BaseConverter(10, intArrayOf(0)) val expectedDigits = intArrayOf(0) val actualDigits = baseConverter.convertToBase(2) assertArrayEquals( "Expected digits: ${Arrays.toString(expectedDigits)} but found digits: ${Arrays.toString(actualDigits)}", expectedDigits, actualDigits) } @Ignore @Test fun testMultipleZeros() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Digits may not contain leading zeros.") BaseConverter(10, intArrayOf(0, 0, 0)) } @Ignore @Test fun testLeadingZeros() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Digits may not contain leading zeros.") BaseConverter(7, intArrayOf(0, 6, 0)) } @Ignore @Test fun testFirstBaseIsOne() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Bases must be at least 2.") BaseConverter(1, intArrayOf(0)) } @Ignore @Test fun testFirstBaseIsZero() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Bases must be at least 2.") BaseConverter(0, intArrayOf()) } @Ignore @Test fun testFirstBaseIsNegative() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Bases must be at least 2.") BaseConverter(-2, intArrayOf(1)) } @Ignore @Test fun testNegativeDigit() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Digits may not be negative.") BaseConverter(2, intArrayOf(1, -1, 1, 0, 1, 0)) } @Ignore @Test fun testInvalidPositiveDigit() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("All digits must be strictly less than the base.") BaseConverter(2, intArrayOf(1, 2, 1, 0, 1, 0)) } @Ignore @Test fun testSecondBaseIsOne() { val baseConverter = BaseConverter(2, intArrayOf(1, 0, 1, 0, 1, 0)) expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Bases must be at least 2.") baseConverter.convertToBase(1) } @Ignore @Test fun testSecondBaseIsZero() { val baseConverter = BaseConverter(2, intArrayOf(1, 0, 1, 0, 1, 0)) expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Bases must be at least 2.") baseConverter.convertToBase(0) } @Ignore @Test fun testSecondBaseIsNegative() { val baseConverter = BaseConverter(2, intArrayOf(1)) expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Bases must be at least 2.") baseConverter.convertToBase(-7) } } ================================================ FILE: exercises/practice/allergies/.docs/instructions.md ================================================ # Instructions Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies. An allergy test produces a single numeric score which contains the information about all the allergies the person has (that they were tested for). The list of items (and their value) that were tested are: - eggs (1) - peanuts (2) - shellfish (4) - strawberries (8) - tomatoes (16) - chocolate (32) - pollen (64) - cats (128) So if Tom is allergic to peanuts and chocolate, he gets a score of 34. Now, given just that score of 34, your program should be able to say: - Whether Tom is allergic to any one of those allergens listed above. - All the allergens Tom is allergic to. Note: a given score may include allergens **not** listed above (i.e. allergens that score 256, 512, 1024, etc.). Your program should ignore those components of the score. For example, if the allergy score is 257, your program should only report the eggs (1) allergy. ================================================ FILE: exercises/practice/allergies/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Allergies.kt" ], "test": [ "src/test/kotlin/AllergiesTest.kt" ], "example": [ ".meta/src/reference/kotlin/Allergies.kt" ] }, "blurb": "Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies.", "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", "source_url": "https://turing.edu" } ================================================ FILE: exercises/practice/allergies/.meta/src/reference/kotlin/Allergen.kt ================================================ enum class Allergen(val score: Int) { EGGS(1), PEANUTS(2), SHELLFISH(4), STRAWBERRIES(8), TOMATOES(16), CHOCOLATE(32), POLLEN(64), CATS(128) } ================================================ FILE: exercises/practice/allergies/.meta/src/reference/kotlin/Allergies.kt ================================================ class Allergies(val score: Int) { fun getList(): List = Allergen.values().filter { isAllergicTo(it) } fun isAllergicTo(allergen: Allergen) = (score and allergen.score) == allergen.score } ================================================ FILE: exercises/practice/allergies/.meta/tests.toml ================================================ [canonical-tests] # not allergic to anything "17fc7296-2440-4ac4-ad7b-d07c321bc5a0" = true # allergic only to eggs "07ced27b-1da5-4c2e-8ae2-cb2791437546" = true # allergic to eggs and something else "5035b954-b6fa-4b9b-a487-dae69d8c5f96" = true # allergic to something, but not eggs "64a6a83a-5723-4b5b-a896-663307403310" = true # allergic to everything "90c8f484-456b-41c4-82ba-2d08d93231c6" = true # not allergic to anything "d266a59a-fccc-413b-ac53-d57cb1f0db9d" = true # allergic only to peanuts "ea210a98-860d-46b2-a5bf-50d8995b3f2a" = true # allergic to peanuts and something else "eac69ae9-8d14-4291-ac4b-7fd2c73d3a5b" = true # allergic to something, but not peanuts "9152058c-ce39-4b16-9b1d-283ec6d25085" = true # allergic to everything "d2d71fd8-63d5-40f9-a627-fbdaf88caeab" = true # not allergic to anything "b948b0a1-cbf7-4b28-a244-73ff56687c80" = true # allergic only to shellfish "9ce9a6f3-53e9-4923-85e0-73019047c567" = true # allergic to shellfish and something else "b272fca5-57ba-4b00-bd0c-43a737ab2131" = true # allergic to something, but not shellfish "21ef8e17-c227-494e-8e78-470a1c59c3d8" = true # allergic to everything "cc789c19-2b5e-4c67-b146-625dc8cfa34e" = true # not allergic to anything "651bde0a-2a74-46c4-ab55-02a0906ca2f5" = true # allergic only to strawberries "b649a750-9703-4f5f-b7f7-91da2c160ece" = true # allergic to strawberries and something else "50f5f8f3-3bac-47e6-8dba-2d94470a4bc6" = true # allergic to something, but not strawberries "23dd6952-88c9-48d7-a7d5-5d0343deb18d" = true # allergic to everything "74afaae2-13b6-43a2-837a-286cd42e7d7e" = true # not allergic to anything "c49a91ef-6252-415e-907e-a9d26ef61723" = true # allergic only to tomatoes "b69c5131-b7d0-41ad-a32c-e1b2cc632df8" = true # allergic to tomatoes and something else "1ca50eb1-f042-4ccf-9050-341521b929ec" = true # allergic to something, but not tomatoes "e9846baa-456b-4eff-8025-034b9f77bd8e" = true # allergic to everything "b2414f01-f3ad-4965-8391-e65f54dad35f" = true # not allergic to anything "978467ab-bda4-49f7-b004-1d011ead947c" = true # allergic only to chocolate "59cf4e49-06ea-4139-a2c1-d7aad28f8cbc" = true # allergic to chocolate and something else "b0a7c07b-2db7-4f73-a180-565e07040ef1" = true # allergic to something, but not chocolate "f5506893-f1ae-482a-b516-7532ba5ca9d2" = true # allergic to everything "02debb3d-d7e2-4376-a26b-3c974b6595c6" = true # not allergic to anything "17f4a42b-c91e-41b8-8a76-4797886c2d96" = true # allergic only to pollen "7696eba7-1837-4488-882a-14b7b4e3e399" = true # allergic to pollen and something else "9a49aec5-fa1f-405d-889e-4dfc420db2b6" = true # allergic to something, but not pollen "3cb8e79f-d108-4712-b620-aa146b1954a9" = true # allergic to everything "1dc3fe57-7c68-4043-9d51-5457128744b2" = true # not allergic to anything "d3f523d6-3d50-419b-a222-d4dfd62ce314" = true # allergic only to cats "eba541c3-c886-42d3-baef-c048cb7fcd8f" = true # allergic to cats and something else "ba718376-26e0-40b7-bbbe-060287637ea5" = true # allergic to something, but not cats "3c6dbf4a-5277-436f-8b88-15a206f2d6c4" = true # allergic to everything "1faabb05-2b98-4995-9046-d83e4a48a7c1" = true # no allergies "f9c1b8e7-7dc5-4887-aa93-cebdcc29dd8f" = true # just eggs "9e1a4364-09a6-4d94-990f-541a94a4c1e8" = true # just peanuts "8851c973-805e-4283-9e01-d0c0da0e4695" = true # just strawberries "2c8943cb-005e-435f-ae11-3e8fb558ea98" = true # eggs and peanuts "6fa95d26-044c-48a9-8a7b-9ee46ec32c5c" = true # more than eggs but not peanuts "19890e22-f63f-4c5c-a9fb-fb6eacddfe8e" = true # lots of stuff "4b68f470-067c-44e4-889f-c9fe28917d2f" = true # everything "0881b7c5-9efa-4530-91bd-68370d054bc7" = true # no allergen score parts "12ce86de-b347-42a0-ab7c-2e0570f0c65b" = true ================================================ FILE: exercises/practice/allergies/.meta/version ================================================ 2.0.0 ================================================ FILE: exercises/practice/allergies/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/allergies/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/allergies/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/allergies/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/allergies/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/allergies/src/main/kotlin/Allergen.kt ================================================ enum class Allergen(val score: Int) { EGGS(1), PEANUTS(2), SHELLFISH(4), STRAWBERRIES(8), TOMATOES(16), CHOCOLATE(32), POLLEN(64), CATS(128) } ================================================ FILE: exercises/practice/allergies/src/main/kotlin/Allergies.kt ================================================ class Allergies { // TODO: implement proper constructor to complete the task fun getList(): List { TODO("Implement the function to complete the task") } fun isAllergicTo(allergen: Allergen) { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/allergies/src/test/kotlin/AllergiesTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue class AllergiesTest { @Test fun `eggs - not allergic to anything`() = assertIsNotAllergic(0, Allergen.EGGS) @Ignore @Test fun `eggs - allergic only to eggs`() = assertIsAllergic(1, Allergen.EGGS) @Ignore @Test fun `eggs - allergic to eggs and something else`() = assertIsAllergic(3, Allergen.EGGS) @Ignore @Test fun `eggs - allergic to something, but not eggs`() = assertIsNotAllergic(2, Allergen.EGGS) @Ignore @Test fun `eggs - allergic to everything`() = assertIsAllergic(255, Allergen.EGGS) @Ignore @Test fun `peanuts - not allergic to anything`() = assertIsNotAllergic(0, Allergen.PEANUTS) @Ignore @Test fun `peanuts - allergic only to peanuts`() = assertIsAllergic(2, Allergen.PEANUTS) @Ignore @Test fun `peanuts - allergic to peanuts and something else`() = assertIsAllergic(7, Allergen.PEANUTS) @Ignore @Test fun `peanuts - allergic to something, but not peanuts`() = assertIsNotAllergic(5, Allergen.PEANUTS) @Ignore @Test fun `peanuts - allergic to everything`() = assertIsAllergic(255, Allergen.PEANUTS) @Ignore @Test fun `shellfish - not allergic to anything`() = assertIsNotAllergic(0, Allergen.SHELLFISH) @Ignore @Test fun `shellfish - allergic only to shellfish`() = assertIsAllergic(4, Allergen.SHELLFISH) @Ignore @Test fun `shellfish - allergic to shellfish and something else`() = assertIsAllergic(14, Allergen.SHELLFISH) @Ignore @Test fun `shellfish - allergic to something, but not shellfish`() = assertIsNotAllergic(10, Allergen.SHELLFISH) @Ignore @Test fun `shellfish - allergic to everything`() = assertIsAllergic(255, Allergen.SHELLFISH) @Ignore @Test fun `strawberries - not allergic to anything`() = assertIsNotAllergic(0, Allergen.STRAWBERRIES) @Ignore @Test fun `strawberries - allergic only to strawberries`() = assertIsAllergic(8, Allergen.STRAWBERRIES) @Ignore @Test fun `strawberries - allergic to strawberries and something else`() = assertIsAllergic(28, Allergen.STRAWBERRIES) @Ignore @Test fun `strawberries - allergic to something, but not strawberries`() = assertIsNotAllergic(20, Allergen.STRAWBERRIES) @Ignore @Test fun `strawberries - allergic to everything`() = assertIsAllergic(255, Allergen.STRAWBERRIES) @Ignore @Test fun `tomatoes - not allergic to anything`() = assertIsNotAllergic(0, Allergen.TOMATOES) @Ignore @Test fun `tomatoes - allergic only to tomatoes`() = assertIsAllergic(16, Allergen.TOMATOES) @Ignore @Test fun `tomatoes - allergic to tomatoes and something else`() = assertIsAllergic(56, Allergen.TOMATOES) @Ignore @Test fun `tomatoes - allergic to something, but not tomatoes`() = assertIsNotAllergic(40, Allergen.TOMATOES) @Ignore @Test fun `tomatoes - allergic to everything`() = assertIsAllergic(255, Allergen.TOMATOES) @Ignore @Test fun `chocolate - not allergic to anything`() = assertIsNotAllergic(0, Allergen.CHOCOLATE) @Ignore @Test fun `chocolate - allergic only to chocolate`() = assertIsAllergic(32, Allergen.CHOCOLATE) @Ignore @Test fun `chocolate - allergic to chocolate and something else`() = assertIsAllergic(112, Allergen.CHOCOLATE) @Ignore @Test fun `chocolate - allergic to something, but not chocolate`() = assertIsNotAllergic(80, Allergen.CHOCOLATE) @Ignore @Test fun `chocolate - allergic to everything`() = assertIsAllergic(255, Allergen.CHOCOLATE) @Ignore @Test fun `pollen - not allergic to anything`() = assertIsNotAllergic(0, Allergen.POLLEN) @Ignore @Test fun `pollen - allergic only to pollen`() = assertIsAllergic(64, Allergen.POLLEN) @Ignore @Test fun `pollen - allergic to pollen and something else`() = assertIsAllergic(224, Allergen.POLLEN) @Ignore @Test fun `pollen - allergic to something, but not pollen`() = assertIsNotAllergic(160, Allergen.POLLEN) @Ignore @Test fun `pollen - allergic to everything`() = assertIsAllergic(255, Allergen.POLLEN) @Ignore @Test fun `cats - not allergic to anything`() = assertIsNotAllergic(0, Allergen.CATS) @Ignore @Test fun `cats - allergic only to cats`() = assertIsAllergic(128, Allergen.CATS) @Ignore @Test fun `cats - allergic to cats and something else`() = assertIsAllergic(192, Allergen.CATS) @Ignore @Test fun `cats - allergic to something, but not cats`() = assertIsNotAllergic(64, Allergen.CATS) @Ignore @Test fun `cats - allergic to everything`() = assertIsAllergic(255, Allergen.CATS) @Ignore @Test fun `list - no allergies`() = assertAllergens(0, emptyList()) @Ignore @Test fun `list - just eggs`() = assertAllergens( 1, listOf(Allergen.EGGS)) @Ignore @Test fun `list - just peanuts`() = assertAllergens( 2, listOf(Allergen.PEANUTS)) @Ignore @Test fun `list - eggs and peanuts`() = assertAllergens( 3, listOf(Allergen.EGGS, Allergen.PEANUTS)) @Ignore @Test fun `list - more than eggs but not peanuts`() = assertAllergens( 5, listOf(Allergen.EGGS, Allergen.SHELLFISH)) @Ignore @Test fun `list - lots of stuff`() = assertAllergens( 248, listOf(Allergen.STRAWBERRIES, Allergen.TOMATOES, Allergen.CHOCOLATE, Allergen.POLLEN, Allergen.CATS)) @Ignore @Test fun `list - everything`() = assertAllergens( 255, Allergen.values().toList()) @Ignore @Test fun `list - no allergen score parts`() = assertAllergens( 509, Allergen.values().toList() - Allergen.PEANUTS) } private fun assertIsAllergic(score: Int, allergen: Allergen) = assertTrue(Allergies(score).isAllergicTo(allergen)) private fun assertIsNotAllergic(score: Int, allergen: Allergen) = assertFalse(Allergies(score).isAllergicTo(allergen)) private fun assertAllergens(score: Int, allergens: List) = assertEquals(allergens, Allergies(score).getList()) ================================================ FILE: exercises/practice/anagram/.docs/instructions.append.md ================================================ # Instructions Append The anagrams can be returned in any order. ================================================ FILE: exercises/practice/anagram/.docs/instructions.md ================================================ # Instructions Given a target word and one or more candidate words, your task is to find the candidates that are anagrams of the target. An anagram is a rearrangement of letters to form a new word: for example `"owns"` is an anagram of `"snow"`. A word is _not_ its own anagram: for example, `"stop"` is not an anagram of `"stop"`. The target word and candidate words are made up of one or more ASCII alphabetic characters (`A`-`Z` and `a`-`z`). Lowercase and uppercase characters are equivalent: for example, `"PoTS"` is an anagram of `"sTOp"`, but `"StoP"` is not an anagram of `"sTOp"`. The words you need to find should be taken from the candidate words, using the same letter case. Given the target `"stone"` and the candidate words `"stone"`, `"tones"`, `"banana"`, `"tons"`, `"notes"`, and `"Seton"`, the anagram words you need to find are `"tones"`, `"notes"`, and `"Seton"`. ================================================ FILE: exercises/practice/anagram/.docs/introduction.md ================================================ # Introduction At a garage sale, you find a lovely vintage typewriter at a bargain price! Excitedly, you rush home, insert a sheet of paper, and start typing away. However, your excitement wanes when you examine the output: all words are garbled! For example, it prints "stop" instead of "post" and "least" instead of "stale." Carefully, you try again, but now it prints "spot" and "slate." After some experimentation, you find there is a random delay before each letter is printed, which messes up the order. You now understand why they sold it for so little money! You realize this quirk allows you to generate anagrams, which are words formed by rearranging the letters of another word. Pleased with your finding, you spend the rest of the day generating hundreds of anagrams. ================================================ FILE: exercises/practice/anagram/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "sup95", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Anagram.kt" ], "test": [ "src/test/kotlin/AnagramTest.kt" ], "example": [ ".meta/src/reference/kotlin/Anagram.kt" ] }, "blurb": "Given a word and a list of possible anagrams, select the correct sublist.", "source": "Inspired by the Extreme Startup game", "source_url": "https://github.com/rchatley/extreme_startup" } ================================================ FILE: exercises/practice/anagram/.meta/src/reference/kotlin/Anagram.kt ================================================ class Anagram(private val word: String) { fun match(anagrams: Collection) = anagrams.filter { containSameChars(it.lowercase()) } .filterNot { it.equals(word, ignoreCase = true) } .toSet() private fun containSameChars(candidate: String) = candidate.lowercase().toCharArray().sorted() == word.lowercase().toCharArray().sorted() } ================================================ FILE: exercises/practice/anagram/.meta/tests.toml ================================================ [canonical-tests] # no matches "dd40c4d2-3c8b-44e5-992a-f42b393ec373" = true # detects two anagrams "b3cca662-f50a-489e-ae10-ab8290a09bdc" = true # does not detect anagram subsets "a27558ee-9ba0-4552-96b1-ecf665b06556" = true # detects anagram "64cd4584-fc15-4781-b633-3d814c4941a4" = true # detects three anagrams "99c91beb-838f-4ccd-b123-935139917283" = true # detects multiple anagrams with different case "78487770-e258-4e1f-a646-8ece10950d90" = true # does not detect non-anagrams with identical checksum "1d0ab8aa-362f-49b7-9902-3d0c668d557b" = true # detects anagrams case-insensitively "9e632c0b-c0b1-4804-8cc1-e295dea6d8a8" = true # detects anagrams using case-insensitive subject "b248e49f-0905-48d2-9c8d-bd02d8c3e392" = true # detects anagrams using case-insensitive possible matches "f367325c-78ec-411c-be76-e79047f4bd54" = true # does not detect an anagram if the original word is repeated "7cc195ad-e3c7-44ee-9fd2-d3c344806a2c" = true # anagrams must use all letters exactly once "9878a1c9-d6ea-4235-ae51-3ea2befd6842" = true # words are not anagrams of themselves (case-insensitive) "85757361-4535-45fd-ac0e-3810d40debc1" = true # words other than themselves can be anagrams "a0705568-628c-4b55-9798-82e4acde51ca" = true ================================================ FILE: exercises/practice/anagram/.meta/version ================================================ 1.5.0 ================================================ FILE: exercises/practice/anagram/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/anagram/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/anagram/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/anagram/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/anagram/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/anagram/src/main/kotlin/Anagram.kt ================================================ class Anagram { // TODO: implement proper constructor to complete the task fun match(anagrams: Collection): Set { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/anagram/src/test/kotlin/AnagramTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals import kotlin.test.assertTrue class AnagramTest { @Test fun `no matches`() = anagramsOf("diaper") .searchedIn("hello", "world", "zombies", "pants") .shouldBeEmpty() @Ignore @Test fun `detects two anagrams`() = anagramsOf("master") .searchedIn("stream", "pigeon", "maters") .shouldBeOnly("maters", "stream") @Ignore @Test fun `does not detect anagram subsets`() = anagramsOf("good") .searchedIn("dog", "goody") .shouldBeEmpty() @Ignore @Test fun `detects anagram`() = anagramsOf("listen") .searchedIn("enlists", "google", "inlets", "banana") .shouldBeOnly("inlets") @Ignore @Test fun `detects three anagrams`() = anagramsOf("allergy") .searchedIn("gallery", "ballerina", "regally", "clergy", "largely", "leading") .shouldBeOnly("gallery", "largely", "regally") @Ignore @Test fun `detects multiple anagrams with different case`() = anagramsOf("nose") .searchedIn("Eons", "ONES") .shouldBeOnly("Eons", "ONES") @Ignore @Test fun `does not detect non-anagrams with identical checksum`() = anagramsOf("mass") .searchedIn("last") .shouldBeEmpty() @Ignore @Test fun `detects anagrams case-insensitively`() = anagramsOf("Orchestra") .searchedIn("cashregister", "Carthorse", "radishes") .shouldBeOnly("Carthorse") @Ignore @Test fun `detects anagrams using case-insensitive subject`() = anagramsOf("Orchestra") .searchedIn("cashregister", "carthorse", "radishes") .shouldBeOnly("carthorse") @Ignore @Test fun `detects anagrams using case-insensitive possible matches`() = anagramsOf("orchestra") .searchedIn("cashregister", "Carthorse", "radishes") .shouldBeOnly("Carthorse") @Ignore @Test fun `does not detect an anagram if the original word is repeated`() = anagramsOf("go") .searchedIn("go Go GO") .shouldBeEmpty() @Ignore @Test fun `anagrams must use all letters exactly once`() = anagramsOf("tapper") .searchedIn("patter") .shouldBeEmpty() @Ignore @Test fun `words are not anagrams of themselves (case-insensitive)`() = anagramsOf("BANANA") .searchedIn("Banana") .shouldBeEmpty() @Ignore @Test fun `words other than themselves can be anagrams`() = anagramsOf("LISTEN") .searchedIn("Listen", "Silent", "LISTEN") .shouldBeOnly("Silent") } private fun anagramsOf(source: String) = Anagram(source) private fun Anagram.searchedIn(vararg variants: String) = this.match(setOf(*variants)) private fun Set.shouldBeOnly(vararg expectation: String) = assertEquals(setOf(*expectation), this) private fun Set.shouldBeEmpty() = assertTrue(this.isEmpty()) ================================================ FILE: exercises/practice/armstrong-numbers/.docs/instructions.md ================================================ # Instructions An [Armstrong number][armstrong-number] is a number that is the sum of its own digits each raised to the power of the number of digits. For example: - 9 is an Armstrong number, because `9 = 9^1 = 9` - 10 is _not_ an Armstrong number, because `10 != 1^2 + 0^2 = 1` - 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153` - 154 is _not_ an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` Write some code to determine whether a number is an Armstrong number. [armstrong-number]: https://en.wikipedia.org/wiki/Narcissistic_number ================================================ FILE: exercises/practice/armstrong-numbers/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ArmstrongNumber.kt" ], "test": [ "src/test/kotlin/ArmstrongNumberTest.kt" ], "example": [ ".meta/src/reference/kotlin/ArmstrongNumber.kt" ] }, "blurb": "Determine if a number is an Armstrong number.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Narcissistic_number" } ================================================ FILE: exercises/practice/armstrong-numbers/.meta/src/reference/kotlin/ArmstrongNumber.kt ================================================ import java.math.BigInteger object ArmstrongNumber { fun check(input: Long): Boolean { val str = input.toString() val inputLength = str.length val calculated = str .map { Character.getNumericValue(it) } // digit character to its numeric (not ASCII!) value .sumOf { BigInteger.valueOf(it.toLong()).pow(inputLength).toLong() } // calculate digit^inputLength return input == calculated } } ================================================ FILE: exercises/practice/armstrong-numbers/.meta/tests.toml ================================================ [canonical-tests] # Zero is an Armstrong number "c1ed103c-258d-45b2-be73-d8c6d9580c7b" = true # Single digit numbers are Armstrong numbers "579e8f03-9659-4b85-a1a2-d64350f6b17a" = true # There are no 2 digit Armstrong numbers "2d6db9dc-5bf8-4976-a90b-b2c2b9feba60" = true # Three digit number that is an Armstrong number "509c087f-e327-4113-a7d2-26a4e9d18283" = true # Three digit number that is not an Armstrong number "7154547d-c2ce-468d-b214-4cb953b870cf" = true # Four digit number that is an Armstrong number "6bac5b7b-42e9-4ecb-a8b0-4832229aa103" = true # Four digit number that is not an Armstrong number "eed4b331-af80-45b5-a80b-19c9ea444b2e" = true # Seven digit number that is an Armstrong number "f971ced7-8d68-4758-aea1-d4194900b864" = true # Seven digit number that is not an Armstrong number "7ee45d52-5d35-4fbd-b6f1-5c8cd8a67f18" = true ================================================ FILE: exercises/practice/armstrong-numbers/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/armstrong-numbers/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/armstrong-numbers/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/armstrong-numbers/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/armstrong-numbers/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/armstrong-numbers/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/armstrong-numbers/src/main/kotlin/ArmstrongNumber.kt ================================================ object ArmstrongNumber { fun check(input: Int): Boolean { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/armstrong-numbers/src/test/kotlin/ArmstrongNumberTest.kt ================================================ import kotlin.test.Test import kotlin.test.assertTrue import kotlin.test.assertFalse import kotlin.test.Ignore class ArmstrongNumberTest { @Test fun `zero is an armstrong number`() = assertTrue(ArmstrongNumber.check(0)) @Ignore @Test fun `single digit numbers are armstrong numbers`() = assertTrue(ArmstrongNumber.check(5)) @Ignore @Test fun `there are no 2 digit armstrong numbers`() = assertFalse(ArmstrongNumber.check(10)) @Ignore @Test fun `three digit number that is an armstrong number`() = assertTrue(ArmstrongNumber.check(153)) @Ignore @Test fun `three digit number that is not an armstrong number`() = assertFalse(ArmstrongNumber.check(100)) @Ignore @Test fun `four digit number that is an armstrong number`() = assertTrue(ArmstrongNumber.check(9474)) @Ignore @Test fun `four digit number that is not an armstrong number`() = assertFalse(ArmstrongNumber.check(9475)) @Ignore @Test fun `seven digit number that is an armstrong number`() = assertTrue(ArmstrongNumber.check(9926315)) @Ignore @Test fun `seven digit number that is not an armstrong number`() = assertFalse(ArmstrongNumber.check(9926314)) } ================================================ FILE: exercises/practice/atbash-cipher/.docs/instructions.md ================================================ # Instructions Create an implementation of the Atbash cipher, an ancient encryption system created in the Middle East. The Atbash cipher is a simple substitution cipher that relies on transposing all the letters in the alphabet such that the resulting alphabet is backwards. The first letter is replaced with the last letter, the second with the second-last, and so on. An Atbash cipher for the Latin alphabet would be as follows: ```text Plain: abcdefghijklmnopqrstuvwxyz Cipher: zyxwvutsrqponmlkjihgfedcba ``` It is a very weak cipher because it only has one possible key, and it is a simple mono-alphabetic substitution cipher. However, this may not have been an issue in the cipher's time. Ciphertext is written out in groups of fixed length, the traditional group size being 5 letters, leaving numbers unchanged, and punctuation is excluded. This is to make it harder to guess things based on word boundaries. All text will be encoded as lowercase letters. ## Examples - Encoding `test` gives `gvhg` - Encoding `x123 yes` gives `c123b vh` - Decoding `gvhg` gives `test` - Decoding `gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt` gives `thequickbrownfoxjumpsoverthelazydog` ================================================ FILE: exercises/practice/atbash-cipher/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Atbash.kt" ], "test": [ "src/test/kotlin/AtbashTest.kt" ], "example": [ ".meta/src/reference/kotlin/Atbash.kt" ] }, "blurb": "Create an implementation of the Atbash cipher, an ancient encryption system created in the Middle East.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Atbash" } ================================================ FILE: exercises/practice/atbash-cipher/.meta/src/reference/kotlin/Atbash.kt ================================================ object Atbash { private const val GROUP_SIZE = 5 fun encode(s: String): String = cipherSubstitution(s).mapIndexed { index, char -> char + groupFinalizer(index) }.joinToString("").trimEnd() fun decode(s: String): String = cipherSubstitution(s) private fun cipherSubstitution(s: String): String = s.fold("") { accum, char -> accum + substitute(char) } private fun substitute(c: Char): String { return when { c.isDigit() -> c.toString() c.isLetter() -> ('a' + ('z' - c.lowercaseChar())).toString() else -> "" } } private fun groupFinalizer(index: Int): String = if ((index + 1) % GROUP_SIZE == 0) " " else "" } ================================================ FILE: exercises/practice/atbash-cipher/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [2f47ebe1-eab9-4d6b-b3c6-627562a31c77] description = "encode -> encode yes" [b4ffe781-ea81-4b74-b268-cc58ba21c739] description = "encode -> encode no" [10e48927-24ab-4c4d-9d3f-3067724ace00] description = "encode -> encode OMG" [d59b8bc3-509a-4a9a-834c-6f501b98750b] description = "encode -> encode spaces" [31d44b11-81b7-4a94-8b43-4af6a2449429] description = "encode -> encode mindblowingly" [d503361a-1433-48c0-aae0-d41b5baa33ff] description = "encode -> encode numbers" [79c8a2d5-0772-42d4-b41b-531d0b5da926] description = "encode -> encode deep thought" [9ca13d23-d32a-4967-a1fd-6100b8742bab] description = "encode -> encode all the letters" [bb50e087-7fdf-48e7-9223-284fe7e69851] description = "decode -> decode exercism" [ac021097-cd5d-4717-8907-b0814b9e292c] description = "decode -> decode a sentence" [18729de3-de74-49b8-b68c-025eaf77f851] description = "decode -> decode numbers" [0f30325f-f53b-415d-ad3e-a7a4f63de034] description = "decode -> decode all the letters" [39640287-30c6-4c8c-9bac-9d613d1a5674] description = "decode -> decode with too many spaces" [b34edf13-34c0-49b5-aa21-0768928000d5] description = "decode -> decode with no spaces" ================================================ FILE: exercises/practice/atbash-cipher/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/atbash-cipher/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/atbash-cipher/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/atbash-cipher/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/atbash-cipher/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/atbash-cipher/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/atbash-cipher/src/main/kotlin/Atbash.kt ================================================ object Atbash { fun encode(s: String): String{ TODO("Implement the function to complete the task") } fun decode(s: String): String{ TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/atbash-cipher/src/test/kotlin/AtbashTest.kt ================================================ import org.junit.Test import org.junit.Ignore import org.junit.experimental.runners.Enclosed import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals @RunWith(Enclosed::class) class AtbashTest { @RunWith(Parameterized::class) class EncodeTest(val input: String, val expectedOutput: String) { companion object { @JvmStatic @Parameterized.Parameters (name = "{index}: encode({0}) = {1}") fun data() = listOf( arrayOf("yes", "bvh"), arrayOf("no", "ml"), arrayOf("OMG", "lnt"), arrayOf("O M G", "lnt"), arrayOf("mindblowingly", "nrmwy oldrm tob"), arrayOf("Testing,1 2 3, testing.", "gvhgr mt123 gvhgr mt"), arrayOf("Truth is fiction.", "gifgs rhurx grlm"), arrayOf("The quick brown fox jumps over the lazy dog.", "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt") ) } @Test fun test() { assertEquals(expectedOutput, Atbash.encode(input)) } } @RunWith(Parameterized::class) class DecodeTest(val input: String, val expectedOutput: String) { companion object { @JvmStatic @Parameterized.Parameters(name = "{index}: decode({0}) = {1}") fun data() = listOf( arrayOf("vcvix rhn", "exercism"), arrayOf("zmlyh gzxov rhlug vmzhg vkkrm thglm v", "anobstacleisoftenasteppingstone"), arrayOf("gvhgr mt123 gvhgr mt", "testing123testing"), arrayOf("gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt", "thequickbrownfoxjumpsoverthelazydog"), arrayOf("vc vix r hn", "exercism"), arrayOf("zmlyhgzxovrhlugvmzhgvkkrmthglmv", "anobstacleisoftenasteppingstone") ) } @Ignore @Test fun test() { assertEquals(expectedOutput, Atbash.decode(input)) } } } ================================================ FILE: exercises/practice/bank-account/.docs/instructions.md ================================================ # Instructions Your task is to implement bank accounts supporting opening/closing, withdrawals, and deposits of money. As bank accounts can be accessed in many different ways (internet, mobile phones, automatic charges), your bank software must allow accounts to be safely accessed from multiple threads/processes (terminology depends on your programming language) in parallel. For example, there may be many deposits and withdrawals occurring in parallel; you need to ensure there are no [race conditions][wikipedia] between when you read the account balance and set the new balance. It should be possible to close an account; operations against a closed account must fail. [wikipedia]: https://en.wikipedia.org/wiki/Race_condition#In_software ================================================ FILE: exercises/practice/bank-account/.docs/introduction.md ================================================ # Introduction After years of filling out forms and waiting, you've finally acquired your banking license. This means you are now officially eligible to open your own bank, hurray! Your first priority is to get the IT systems up and running. After a day of hard work, you can already open and close accounts, as well as handle withdrawals and deposits. Since you couldn't be bothered writing tests, you invite some friends to help test the system. However, after just five minutes, one of your friends claims they've lost money! While you're confident your code is bug-free, you start looking through the logs to investigate. Ah yes, just as you suspected, your friend is at fault! They shared their test credentials with another friend, and together they conspired to make deposits and withdrawals from the same account _in parallel_. Who would do such a thing? While you argue that it's physically _impossible_ for someone to access their account in parallel, your friend smugly notifies you that the banking rules _require_ you to support this. Thus, no parallel banking support, no go-live signal. Sighing, you create a mental note to work on this tomorrow. This will set your launch date back at _least_ one more day, but well... ================================================ FILE: exercises/practice/bank-account/.meta/config.json ================================================ { "authors": [ "nithia" ], "contributors": [ "araknoid", "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/BankAccount.kt" ], "test": [ "src/test/kotlin/BankAccountTest.kt" ], "example": [ ".meta/src/reference/kotlin/BankAccount.kt" ] }, "test_runner": false, "blurb": "Simulate a bank account supporting opening/closing, withdraws, and deposits of money. Watch out for concurrent transactions!" } ================================================ FILE: exercises/practice/bank-account/.meta/src/reference/kotlin/BankAccount.kt ================================================ class BankAccount { var balance: Long = 0 get() { synchronized(lock) { if (!isOpen) throw IllegalStateException("Account is closed") return field } } private set var isOpen = true private set fun adjustBalance(amount: Long) { synchronized(lock) { balance += amount } } fun close() { synchronized(lock) { isOpen = false } } private val lock = Any() } ================================================ FILE: exercises/practice/bank-account/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/bank-account/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/bank-account/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/bank-account/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/bank-account/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/bank-account/src/main/kotlin/BankAccount.kt ================================================ class BankAccount { // TODO: implement read access to 'balance' fun adjustBalance(amount: Long){ TODO("Implement the function to complete the task") } fun close() { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/bank-account/src/test/kotlin/BankAccountTest.kt ================================================ import org.junit.Ignore import org.junit.Test import java.util.* import java.util.concurrent.Executors import java.util.concurrent.TimeUnit import kotlin.test.assertEquals import kotlin.test.assertFailsWith class BankAccountTest { @Test fun zeroBalanceWhenOpened() { val account = BankAccount() assertEquals(0, account.balance) } @Ignore @Test fun sequentialBalanceAdjustments() { val account = BankAccount() account.adjustBalance(1000) assertEquals(1000, account.balance) account.adjustBalance(-958) assertEquals(42, account.balance) } @Ignore @Test fun closedAccountHasNoBalance() { val account = BankAccount() account.close() assertFailsWith(IllegalStateException::class) { account.balance } } @Ignore @Test fun closedAccountCannotBeAdjusted() { val account = BankAccount() account.close() assertFailsWith(IllegalStateException::class) { account.adjustBalance(1000) } } @Ignore @Test fun concurrentBalanceAdjustments() { val threads = 100 val iterations = 500 val random = Random() val account = BankAccount() val executor = Executors.newFixedThreadPool(8) repeat(threads) { executor.submit { repeat(iterations) { account.adjustBalance(1) Thread.sleep(random.nextInt(10).toLong()) account.adjustBalance(-1) } } } executor.shutdown() executor.awaitTermination(10, TimeUnit.MINUTES) assertEquals(0, account.balance) } } ================================================ FILE: exercises/practice/beer-song/.docs/instructions.md ================================================ # Instructions Recite the lyrics to that beloved classic, that field-trip favorite: 99 Bottles of Beer on the Wall. Note that not all verses are identical. ```text 99 bottles of beer on the wall, 99 bottles of beer. Take one down and pass it around, 98 bottles of beer on the wall. 98 bottles of beer on the wall, 98 bottles of beer. Take one down and pass it around, 97 bottles of beer on the wall. 97 bottles of beer on the wall, 97 bottles of beer. Take one down and pass it around, 96 bottles of beer on the wall. 96 bottles of beer on the wall, 96 bottles of beer. Take one down and pass it around, 95 bottles of beer on the wall. 95 bottles of beer on the wall, 95 bottles of beer. Take one down and pass it around, 94 bottles of beer on the wall. 94 bottles of beer on the wall, 94 bottles of beer. Take one down and pass it around, 93 bottles of beer on the wall. 93 bottles of beer on the wall, 93 bottles of beer. Take one down and pass it around, 92 bottles of beer on the wall. 92 bottles of beer on the wall, 92 bottles of beer. Take one down and pass it around, 91 bottles of beer on the wall. 91 bottles of beer on the wall, 91 bottles of beer. Take one down and pass it around, 90 bottles of beer on the wall. 90 bottles of beer on the wall, 90 bottles of beer. Take one down and pass it around, 89 bottles of beer on the wall. 89 bottles of beer on the wall, 89 bottles of beer. Take one down and pass it around, 88 bottles of beer on the wall. 88 bottles of beer on the wall, 88 bottles of beer. Take one down and pass it around, 87 bottles of beer on the wall. 87 bottles of beer on the wall, 87 bottles of beer. Take one down and pass it around, 86 bottles of beer on the wall. 86 bottles of beer on the wall, 86 bottles of beer. Take one down and pass it around, 85 bottles of beer on the wall. 85 bottles of beer on the wall, 85 bottles of beer. Take one down and pass it around, 84 bottles of beer on the wall. 84 bottles of beer on the wall, 84 bottles of beer. Take one down and pass it around, 83 bottles of beer on the wall. 83 bottles of beer on the wall, 83 bottles of beer. Take one down and pass it around, 82 bottles of beer on the wall. 82 bottles of beer on the wall, 82 bottles of beer. Take one down and pass it around, 81 bottles of beer on the wall. 81 bottles of beer on the wall, 81 bottles of beer. Take one down and pass it around, 80 bottles of beer on the wall. 80 bottles of beer on the wall, 80 bottles of beer. Take one down and pass it around, 79 bottles of beer on the wall. 79 bottles of beer on the wall, 79 bottles of beer. Take one down and pass it around, 78 bottles of beer on the wall. 78 bottles of beer on the wall, 78 bottles of beer. Take one down and pass it around, 77 bottles of beer on the wall. 77 bottles of beer on the wall, 77 bottles of beer. Take one down and pass it around, 76 bottles of beer on the wall. 76 bottles of beer on the wall, 76 bottles of beer. Take one down and pass it around, 75 bottles of beer on the wall. 75 bottles of beer on the wall, 75 bottles of beer. Take one down and pass it around, 74 bottles of beer on the wall. 74 bottles of beer on the wall, 74 bottles of beer. Take one down and pass it around, 73 bottles of beer on the wall. 73 bottles of beer on the wall, 73 bottles of beer. Take one down and pass it around, 72 bottles of beer on the wall. 72 bottles of beer on the wall, 72 bottles of beer. Take one down and pass it around, 71 bottles of beer on the wall. 71 bottles of beer on the wall, 71 bottles of beer. Take one down and pass it around, 70 bottles of beer on the wall. 70 bottles of beer on the wall, 70 bottles of beer. Take one down and pass it around, 69 bottles of beer on the wall. 69 bottles of beer on the wall, 69 bottles of beer. Take one down and pass it around, 68 bottles of beer on the wall. 68 bottles of beer on the wall, 68 bottles of beer. Take one down and pass it around, 67 bottles of beer on the wall. 67 bottles of beer on the wall, 67 bottles of beer. Take one down and pass it around, 66 bottles of beer on the wall. 66 bottles of beer on the wall, 66 bottles of beer. Take one down and pass it around, 65 bottles of beer on the wall. 65 bottles of beer on the wall, 65 bottles of beer. Take one down and pass it around, 64 bottles of beer on the wall. 64 bottles of beer on the wall, 64 bottles of beer. Take one down and pass it around, 63 bottles of beer on the wall. 63 bottles of beer on the wall, 63 bottles of beer. Take one down and pass it around, 62 bottles of beer on the wall. 62 bottles of beer on the wall, 62 bottles of beer. Take one down and pass it around, 61 bottles of beer on the wall. 61 bottles of beer on the wall, 61 bottles of beer. Take one down and pass it around, 60 bottles of beer on the wall. 60 bottles of beer on the wall, 60 bottles of beer. Take one down and pass it around, 59 bottles of beer on the wall. 59 bottles of beer on the wall, 59 bottles of beer. Take one down and pass it around, 58 bottles of beer on the wall. 58 bottles of beer on the wall, 58 bottles of beer. Take one down and pass it around, 57 bottles of beer on the wall. 57 bottles of beer on the wall, 57 bottles of beer. Take one down and pass it around, 56 bottles of beer on the wall. 56 bottles of beer on the wall, 56 bottles of beer. Take one down and pass it around, 55 bottles of beer on the wall. 55 bottles of beer on the wall, 55 bottles of beer. Take one down and pass it around, 54 bottles of beer on the wall. 54 bottles of beer on the wall, 54 bottles of beer. Take one down and pass it around, 53 bottles of beer on the wall. 53 bottles of beer on the wall, 53 bottles of beer. Take one down and pass it around, 52 bottles of beer on the wall. 52 bottles of beer on the wall, 52 bottles of beer. Take one down and pass it around, 51 bottles of beer on the wall. 51 bottles of beer on the wall, 51 bottles of beer. Take one down and pass it around, 50 bottles of beer on the wall. 50 bottles of beer on the wall, 50 bottles of beer. Take one down and pass it around, 49 bottles of beer on the wall. 49 bottles of beer on the wall, 49 bottles of beer. Take one down and pass it around, 48 bottles of beer on the wall. 48 bottles of beer on the wall, 48 bottles of beer. Take one down and pass it around, 47 bottles of beer on the wall. 47 bottles of beer on the wall, 47 bottles of beer. Take one down and pass it around, 46 bottles of beer on the wall. 46 bottles of beer on the wall, 46 bottles of beer. Take one down and pass it around, 45 bottles of beer on the wall. 45 bottles of beer on the wall, 45 bottles of beer. Take one down and pass it around, 44 bottles of beer on the wall. 44 bottles of beer on the wall, 44 bottles of beer. Take one down and pass it around, 43 bottles of beer on the wall. 43 bottles of beer on the wall, 43 bottles of beer. Take one down and pass it around, 42 bottles of beer on the wall. 42 bottles of beer on the wall, 42 bottles of beer. Take one down and pass it around, 41 bottles of beer on the wall. 41 bottles of beer on the wall, 41 bottles of beer. Take one down and pass it around, 40 bottles of beer on the wall. 40 bottles of beer on the wall, 40 bottles of beer. Take one down and pass it around, 39 bottles of beer on the wall. 39 bottles of beer on the wall, 39 bottles of beer. Take one down and pass it around, 38 bottles of beer on the wall. 38 bottles of beer on the wall, 38 bottles of beer. Take one down and pass it around, 37 bottles of beer on the wall. 37 bottles of beer on the wall, 37 bottles of beer. Take one down and pass it around, 36 bottles of beer on the wall. 36 bottles of beer on the wall, 36 bottles of beer. Take one down and pass it around, 35 bottles of beer on the wall. 35 bottles of beer on the wall, 35 bottles of beer. Take one down and pass it around, 34 bottles of beer on the wall. 34 bottles of beer on the wall, 34 bottles of beer. Take one down and pass it around, 33 bottles of beer on the wall. 33 bottles of beer on the wall, 33 bottles of beer. Take one down and pass it around, 32 bottles of beer on the wall. 32 bottles of beer on the wall, 32 bottles of beer. Take one down and pass it around, 31 bottles of beer on the wall. 31 bottles of beer on the wall, 31 bottles of beer. Take one down and pass it around, 30 bottles of beer on the wall. 30 bottles of beer on the wall, 30 bottles of beer. Take one down and pass it around, 29 bottles of beer on the wall. 29 bottles of beer on the wall, 29 bottles of beer. Take one down and pass it around, 28 bottles of beer on the wall. 28 bottles of beer on the wall, 28 bottles of beer. Take one down and pass it around, 27 bottles of beer on the wall. 27 bottles of beer on the wall, 27 bottles of beer. Take one down and pass it around, 26 bottles of beer on the wall. 26 bottles of beer on the wall, 26 bottles of beer. Take one down and pass it around, 25 bottles of beer on the wall. 25 bottles of beer on the wall, 25 bottles of beer. Take one down and pass it around, 24 bottles of beer on the wall. 24 bottles of beer on the wall, 24 bottles of beer. Take one down and pass it around, 23 bottles of beer on the wall. 23 bottles of beer on the wall, 23 bottles of beer. Take one down and pass it around, 22 bottles of beer on the wall. 22 bottles of beer on the wall, 22 bottles of beer. Take one down and pass it around, 21 bottles of beer on the wall. 21 bottles of beer on the wall, 21 bottles of beer. Take one down and pass it around, 20 bottles of beer on the wall. 20 bottles of beer on the wall, 20 bottles of beer. Take one down and pass it around, 19 bottles of beer on the wall. 19 bottles of beer on the wall, 19 bottles of beer. Take one down and pass it around, 18 bottles of beer on the wall. 18 bottles of beer on the wall, 18 bottles of beer. Take one down and pass it around, 17 bottles of beer on the wall. 17 bottles of beer on the wall, 17 bottles of beer. Take one down and pass it around, 16 bottles of beer on the wall. 16 bottles of beer on the wall, 16 bottles of beer. Take one down and pass it around, 15 bottles of beer on the wall. 15 bottles of beer on the wall, 15 bottles of beer. Take one down and pass it around, 14 bottles of beer on the wall. 14 bottles of beer on the wall, 14 bottles of beer. Take one down and pass it around, 13 bottles of beer on the wall. 13 bottles of beer on the wall, 13 bottles of beer. Take one down and pass it around, 12 bottles of beer on the wall. 12 bottles of beer on the wall, 12 bottles of beer. Take one down and pass it around, 11 bottles of beer on the wall. 11 bottles of beer on the wall, 11 bottles of beer. Take one down and pass it around, 10 bottles of beer on the wall. 10 bottles of beer on the wall, 10 bottles of beer. Take one down and pass it around, 9 bottles of beer on the wall. 9 bottles of beer on the wall, 9 bottles of beer. Take one down and pass it around, 8 bottles of beer on the wall. 8 bottles of beer on the wall, 8 bottles of beer. Take one down and pass it around, 7 bottles of beer on the wall. 7 bottles of beer on the wall, 7 bottles of beer. Take one down and pass it around, 6 bottles of beer on the wall. 6 bottles of beer on the wall, 6 bottles of beer. Take one down and pass it around, 5 bottles of beer on the wall. 5 bottles of beer on the wall, 5 bottles of beer. Take one down and pass it around, 4 bottles of beer on the wall. 4 bottles of beer on the wall, 4 bottles of beer. Take one down and pass it around, 3 bottles of beer on the wall. 3 bottles of beer on the wall, 3 bottles of beer. Take one down and pass it around, 2 bottles of beer on the wall. 2 bottles of beer on the wall, 2 bottles of beer. Take one down and pass it around, 1 bottle of beer on the wall. 1 bottle of beer on the wall, 1 bottle of beer. Take it down and pass it around, no more bottles of beer on the wall. No more bottles of beer on the wall, no more bottles of beer. Go to the store and buy some more, 99 bottles of beer on the wall. ``` ================================================ FILE: exercises/practice/beer-song/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/BeerSong.kt" ], "test": [ "src/test/kotlin/BeerSongTest.kt" ], "example": [ ".meta/src/reference/kotlin/BeerSong.kt" ] }, "blurb": "Produce the lyrics to that beloved classic, that field-trip favorite: 99 Bottles of Beer on the Wall.", "source": "Learn to Program by Chris Pine", "source_url": "https://pine.fm/LearnToProgram/?Chapter=06" } ================================================ FILE: exercises/practice/beer-song/.meta/src/reference/kotlin/BeerSong.kt ================================================ object BeerSong { fun verses(startBottles: Int, takeDown: Int) = (startBottles downTo takeDown).joinToString("\n") { verse(it) } private fun verse(number: Int) = when (number) { 0 -> "No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n" 1 -> "1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n" 2 -> "2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n" in 3..99 -> "$number bottles of beer on the wall, $number bottles of beer.\nTake one down and pass it around, ${number - 1} bottles of beer on the wall.\n" else -> throw IllegalArgumentException("Invalid verse number: $number, must be within 0 and 99") } } ================================================ FILE: exercises/practice/beer-song/.meta/tests.toml ================================================ [canonical-tests] # first generic verse "5a02fd08-d336-4607-8006-246fe6fa9fb0" = true # last generic verse "77299ca6-545e-4217-a9cc-606b342e0187" = true # verse with 2 bottles "102cbca0-b197-40fd-b548-e99609b06428" = true # verse with 1 bottle "b8ef9fce-960e-4d85-a0c9-980a04ec1972" = true # verse with 0 bottles "c59d4076-f671-4ee3-baaa-d4966801f90d" = true # first two verses "7e17c794-402d-4ca6-8f96-4d8f6ee1ec7e" = true # last three verses "949868e7-67e8-43d3-9bb4-69277fe020fb" = true # all verses "bc220626-126c-4e72-8df4-fddfc0c3e458" = true ================================================ FILE: exercises/practice/beer-song/.meta/version ================================================ 2.1.0 ================================================ FILE: exercises/practice/beer-song/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/beer-song/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/beer-song/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/beer-song/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/beer-song/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/beer-song/src/main/kotlin/BeerSong.kt ================================================ object BeerSong { fun verses(startBottles: Int, takeDown: Int): String { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/beer-song/src/test/kotlin/BeerSongTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class BeerSongTest { @Test fun firstGenericVerse() { val expected = "99 bottles of beer on the wall, 99 bottles of beer.\nTake one down and pass it around, 98 bottles of beer on the wall.\n" assertEquals(expected, BeerSong.verses(99, 99)) } @Ignore @Test fun lastGenericVerse() { val expected = "3 bottles of beer on the wall, 3 bottles of beer.\nTake one down and pass it around, 2 bottles of beer on the wall.\n" assertEquals(expected, BeerSong.verses(3, 3)) } @Ignore @Test fun verse2() { val expected = "2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n" assertEquals(expected, BeerSong.verses(2, 2)) } @Ignore @Test fun verse1() { val expected = "1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n" assertEquals(expected, BeerSong.verses(1, 1)) } @Ignore @Test fun verse0() { val expected = "No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n" assertEquals(expected, BeerSong.verses(0, 0)) } @Ignore @Test fun firstTwoVerses() { val expected = "99 bottles of beer on the wall, 99 bottles of beer.\nTake one down and pass it around, 98 bottles of beer on the wall.\n\n98 bottles of beer on the wall, 98 bottles of beer.\nTake one down and pass it around, 97 bottles of beer on the wall.\n" assertEquals(expected, BeerSong.verses(99, 98)) } @Ignore @Test fun lastThreeVerses() { val expected = "2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n\n1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n\nNo more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n" assertEquals(expected, BeerSong.verses(2, 0)) } @Ignore @Test fun allVerses() { val expected = """99 bottles of beer on the wall, 99 bottles of beer. Take one down and pass it around, 98 bottles of beer on the wall. 98 bottles of beer on the wall, 98 bottles of beer. Take one down and pass it around, 97 bottles of beer on the wall. 97 bottles of beer on the wall, 97 bottles of beer. Take one down and pass it around, 96 bottles of beer on the wall. 96 bottles of beer on the wall, 96 bottles of beer. Take one down and pass it around, 95 bottles of beer on the wall. 95 bottles of beer on the wall, 95 bottles of beer. Take one down and pass it around, 94 bottles of beer on the wall. 94 bottles of beer on the wall, 94 bottles of beer. Take one down and pass it around, 93 bottles of beer on the wall. 93 bottles of beer on the wall, 93 bottles of beer. Take one down and pass it around, 92 bottles of beer on the wall. 92 bottles of beer on the wall, 92 bottles of beer. Take one down and pass it around, 91 bottles of beer on the wall. 91 bottles of beer on the wall, 91 bottles of beer. Take one down and pass it around, 90 bottles of beer on the wall. 90 bottles of beer on the wall, 90 bottles of beer. Take one down and pass it around, 89 bottles of beer on the wall. 89 bottles of beer on the wall, 89 bottles of beer. Take one down and pass it around, 88 bottles of beer on the wall. 88 bottles of beer on the wall, 88 bottles of beer. Take one down and pass it around, 87 bottles of beer on the wall. 87 bottles of beer on the wall, 87 bottles of beer. Take one down and pass it around, 86 bottles of beer on the wall. 86 bottles of beer on the wall, 86 bottles of beer. Take one down and pass it around, 85 bottles of beer on the wall. 85 bottles of beer on the wall, 85 bottles of beer. Take one down and pass it around, 84 bottles of beer on the wall. 84 bottles of beer on the wall, 84 bottles of beer. Take one down and pass it around, 83 bottles of beer on the wall. 83 bottles of beer on the wall, 83 bottles of beer. Take one down and pass it around, 82 bottles of beer on the wall. 82 bottles of beer on the wall, 82 bottles of beer. Take one down and pass it around, 81 bottles of beer on the wall. 81 bottles of beer on the wall, 81 bottles of beer. Take one down and pass it around, 80 bottles of beer on the wall. 80 bottles of beer on the wall, 80 bottles of beer. Take one down and pass it around, 79 bottles of beer on the wall. 79 bottles of beer on the wall, 79 bottles of beer. Take one down and pass it around, 78 bottles of beer on the wall. 78 bottles of beer on the wall, 78 bottles of beer. Take one down and pass it around, 77 bottles of beer on the wall. 77 bottles of beer on the wall, 77 bottles of beer. Take one down and pass it around, 76 bottles of beer on the wall. 76 bottles of beer on the wall, 76 bottles of beer. Take one down and pass it around, 75 bottles of beer on the wall. 75 bottles of beer on the wall, 75 bottles of beer. Take one down and pass it around, 74 bottles of beer on the wall. 74 bottles of beer on the wall, 74 bottles of beer. Take one down and pass it around, 73 bottles of beer on the wall. 73 bottles of beer on the wall, 73 bottles of beer. Take one down and pass it around, 72 bottles of beer on the wall. 72 bottles of beer on the wall, 72 bottles of beer. Take one down and pass it around, 71 bottles of beer on the wall. 71 bottles of beer on the wall, 71 bottles of beer. Take one down and pass it around, 70 bottles of beer on the wall. 70 bottles of beer on the wall, 70 bottles of beer. Take one down and pass it around, 69 bottles of beer on the wall. 69 bottles of beer on the wall, 69 bottles of beer. Take one down and pass it around, 68 bottles of beer on the wall. 68 bottles of beer on the wall, 68 bottles of beer. Take one down and pass it around, 67 bottles of beer on the wall. 67 bottles of beer on the wall, 67 bottles of beer. Take one down and pass it around, 66 bottles of beer on the wall. 66 bottles of beer on the wall, 66 bottles of beer. Take one down and pass it around, 65 bottles of beer on the wall. 65 bottles of beer on the wall, 65 bottles of beer. Take one down and pass it around, 64 bottles of beer on the wall. 64 bottles of beer on the wall, 64 bottles of beer. Take one down and pass it around, 63 bottles of beer on the wall. 63 bottles of beer on the wall, 63 bottles of beer. Take one down and pass it around, 62 bottles of beer on the wall. 62 bottles of beer on the wall, 62 bottles of beer. Take one down and pass it around, 61 bottles of beer on the wall. 61 bottles of beer on the wall, 61 bottles of beer. Take one down and pass it around, 60 bottles of beer on the wall. 60 bottles of beer on the wall, 60 bottles of beer. Take one down and pass it around, 59 bottles of beer on the wall. 59 bottles of beer on the wall, 59 bottles of beer. Take one down and pass it around, 58 bottles of beer on the wall. 58 bottles of beer on the wall, 58 bottles of beer. Take one down and pass it around, 57 bottles of beer on the wall. 57 bottles of beer on the wall, 57 bottles of beer. Take one down and pass it around, 56 bottles of beer on the wall. 56 bottles of beer on the wall, 56 bottles of beer. Take one down and pass it around, 55 bottles of beer on the wall. 55 bottles of beer on the wall, 55 bottles of beer. Take one down and pass it around, 54 bottles of beer on the wall. 54 bottles of beer on the wall, 54 bottles of beer. Take one down and pass it around, 53 bottles of beer on the wall. 53 bottles of beer on the wall, 53 bottles of beer. Take one down and pass it around, 52 bottles of beer on the wall. 52 bottles of beer on the wall, 52 bottles of beer. Take one down and pass it around, 51 bottles of beer on the wall. 51 bottles of beer on the wall, 51 bottles of beer. Take one down and pass it around, 50 bottles of beer on the wall. 50 bottles of beer on the wall, 50 bottles of beer. Take one down and pass it around, 49 bottles of beer on the wall. 49 bottles of beer on the wall, 49 bottles of beer. Take one down and pass it around, 48 bottles of beer on the wall. 48 bottles of beer on the wall, 48 bottles of beer. Take one down and pass it around, 47 bottles of beer on the wall. 47 bottles of beer on the wall, 47 bottles of beer. Take one down and pass it around, 46 bottles of beer on the wall. 46 bottles of beer on the wall, 46 bottles of beer. Take one down and pass it around, 45 bottles of beer on the wall. 45 bottles of beer on the wall, 45 bottles of beer. Take one down and pass it around, 44 bottles of beer on the wall. 44 bottles of beer on the wall, 44 bottles of beer. Take one down and pass it around, 43 bottles of beer on the wall. 43 bottles of beer on the wall, 43 bottles of beer. Take one down and pass it around, 42 bottles of beer on the wall. 42 bottles of beer on the wall, 42 bottles of beer. Take one down and pass it around, 41 bottles of beer on the wall. 41 bottles of beer on the wall, 41 bottles of beer. Take one down and pass it around, 40 bottles of beer on the wall. 40 bottles of beer on the wall, 40 bottles of beer. Take one down and pass it around, 39 bottles of beer on the wall. 39 bottles of beer on the wall, 39 bottles of beer. Take one down and pass it around, 38 bottles of beer on the wall. 38 bottles of beer on the wall, 38 bottles of beer. Take one down and pass it around, 37 bottles of beer on the wall. 37 bottles of beer on the wall, 37 bottles of beer. Take one down and pass it around, 36 bottles of beer on the wall. 36 bottles of beer on the wall, 36 bottles of beer. Take one down and pass it around, 35 bottles of beer on the wall. 35 bottles of beer on the wall, 35 bottles of beer. Take one down and pass it around, 34 bottles of beer on the wall. 34 bottles of beer on the wall, 34 bottles of beer. Take one down and pass it around, 33 bottles of beer on the wall. 33 bottles of beer on the wall, 33 bottles of beer. Take one down and pass it around, 32 bottles of beer on the wall. 32 bottles of beer on the wall, 32 bottles of beer. Take one down and pass it around, 31 bottles of beer on the wall. 31 bottles of beer on the wall, 31 bottles of beer. Take one down and pass it around, 30 bottles of beer on the wall. 30 bottles of beer on the wall, 30 bottles of beer. Take one down and pass it around, 29 bottles of beer on the wall. 29 bottles of beer on the wall, 29 bottles of beer. Take one down and pass it around, 28 bottles of beer on the wall. 28 bottles of beer on the wall, 28 bottles of beer. Take one down and pass it around, 27 bottles of beer on the wall. 27 bottles of beer on the wall, 27 bottles of beer. Take one down and pass it around, 26 bottles of beer on the wall. 26 bottles of beer on the wall, 26 bottles of beer. Take one down and pass it around, 25 bottles of beer on the wall. 25 bottles of beer on the wall, 25 bottles of beer. Take one down and pass it around, 24 bottles of beer on the wall. 24 bottles of beer on the wall, 24 bottles of beer. Take one down and pass it around, 23 bottles of beer on the wall. 23 bottles of beer on the wall, 23 bottles of beer. Take one down and pass it around, 22 bottles of beer on the wall. 22 bottles of beer on the wall, 22 bottles of beer. Take one down and pass it around, 21 bottles of beer on the wall. 21 bottles of beer on the wall, 21 bottles of beer. Take one down and pass it around, 20 bottles of beer on the wall. 20 bottles of beer on the wall, 20 bottles of beer. Take one down and pass it around, 19 bottles of beer on the wall. 19 bottles of beer on the wall, 19 bottles of beer. Take one down and pass it around, 18 bottles of beer on the wall. 18 bottles of beer on the wall, 18 bottles of beer. Take one down and pass it around, 17 bottles of beer on the wall. 17 bottles of beer on the wall, 17 bottles of beer. Take one down and pass it around, 16 bottles of beer on the wall. 16 bottles of beer on the wall, 16 bottles of beer. Take one down and pass it around, 15 bottles of beer on the wall. 15 bottles of beer on the wall, 15 bottles of beer. Take one down and pass it around, 14 bottles of beer on the wall. 14 bottles of beer on the wall, 14 bottles of beer. Take one down and pass it around, 13 bottles of beer on the wall. 13 bottles of beer on the wall, 13 bottles of beer. Take one down and pass it around, 12 bottles of beer on the wall. 12 bottles of beer on the wall, 12 bottles of beer. Take one down and pass it around, 11 bottles of beer on the wall. 11 bottles of beer on the wall, 11 bottles of beer. Take one down and pass it around, 10 bottles of beer on the wall. 10 bottles of beer on the wall, 10 bottles of beer. Take one down and pass it around, 9 bottles of beer on the wall. 9 bottles of beer on the wall, 9 bottles of beer. Take one down and pass it around, 8 bottles of beer on the wall. 8 bottles of beer on the wall, 8 bottles of beer. Take one down and pass it around, 7 bottles of beer on the wall. 7 bottles of beer on the wall, 7 bottles of beer. Take one down and pass it around, 6 bottles of beer on the wall. 6 bottles of beer on the wall, 6 bottles of beer. Take one down and pass it around, 5 bottles of beer on the wall. 5 bottles of beer on the wall, 5 bottles of beer. Take one down and pass it around, 4 bottles of beer on the wall. 4 bottles of beer on the wall, 4 bottles of beer. Take one down and pass it around, 3 bottles of beer on the wall. 3 bottles of beer on the wall, 3 bottles of beer. Take one down and pass it around, 2 bottles of beer on the wall. 2 bottles of beer on the wall, 2 bottles of beer. Take one down and pass it around, 1 bottle of beer on the wall. 1 bottle of beer on the wall, 1 bottle of beer. Take it down and pass it around, no more bottles of beer on the wall. No more bottles of beer on the wall, no more bottles of beer. Go to the store and buy some more, 99 bottles of beer on the wall. """ assertEquals(expected, BeerSong.verses(99, 0)) } } ================================================ FILE: exercises/practice/binary/.docs/instructions.md ================================================ # Instructions Convert a binary number, represented as a string (e.g. '101010'), to its decimal equivalent using first principles. Implement binary to decimal conversion. Given a binary input string, your program should produce a decimal output. The program should handle invalid inputs. ## Note - Implement the conversion yourself. Do not use something else to perform the conversion for you. ## About Binary (Base-2) Decimal is a base-10 system. A number 23 in base 10 notation can be understood as a linear combination of powers of 10: - The rightmost digit gets multiplied by 10^0 = 1 - The next number gets multiplied by 10^1 = 10 - ... - The *n*th number gets multiplied by 10^*(n-1)*. - All these values are summed. So: `23 => 2*10^1 + 3*10^0 => 2*10 + 3*1 = 23 base 10` Binary is similar, but uses powers of 2 rather than powers of 10. So: `101 => 1*2^2 + 0*2^1 + 1*2^0 => 1*4 + 0*2 + 1*1 => 4 + 1 => 5 base 10`. ================================================ FILE: exercises/practice/binary/.meta/config.json ================================================ { "blurb": "Convert a binary number, represented as a string (e.g. '101010'), to its decimal equivalent using first principles", "authors": ["sdavids13"], "contributors": [ "dector", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": ["src/main/kotlin/Binary.kt"], "test": ["src/test/kotlin/BinaryTest.kt"], "example": [".meta/src/reference/kotlin/Binary.kt"] }, "source": "All of Computer Science", "source_url": "http://www.wolframalpha.com/input/?i=binary&a=*C.binary-_*MathWorld-" } ================================================ FILE: exercises/practice/binary/.meta/src/reference/kotlin/Binary.kt ================================================ object Binary { fun toDecimal(s: String): Int { return s.fold(0) { accum, char -> when (char) { '0' -> accum * 2 '1' -> (accum * 2) + 1 else -> return 0 } } } } ================================================ FILE: exercises/practice/binary/.meta/tests.toml ================================================ [canonical-tests] # binary 0 is decimal 0 "567fc71e-1013-4915-9285-bca0648c0844" = true # binary 1 is decimal 1 "c0824fb1-6a0a-4e9a-a262-c6c00af99fa8" = true # binary 10 is decimal 2 "4d2834fb-3cc3-4159-a8fd-da1098def8ed" = true # binary 11 is decimal 3 "b7b2b649-4a7c-4808-9eb9-caf00529bac6" = true # binary 100 is decimal 4 "de761aff-73cd-43c1-9e1f-0417f07b1e4a" = true # binary 1001 is decimal 9 "7849a8f7-f4a1-4966-963e-503282d6814c" = true # binary 11010 is decimal 26 "836a101c-aecb-473b-ba78-962408dcda98" = true # binary 10001101000 is decimal 1128 "1c6822a4-8584-438b-8dd4-40f0f0b66371" = true # binary ignores leading zeros "91ffe632-8374-4016-b1d1-d8400d9f940d" = true # 2 is not a valid binary digit "44f7d8b1-ddc3-4751-8be3-700a538b421c" = true # a number containing a non-binary digit is invalid "c263a24d-6870-420f-b783-628feefd7b6e" = true # a number with trailing non-binary characters is invalid "8d81305b-0502-4a07-bfba-051c5526d7f2" = true # a number with leading non-binary characters is invalid "a7f79b6b-039a-4d42-99b4-fcee56679f03" = true # a number with internal non-binary characters is invalid "9e0ece9d-b8aa-46a0-a22b-3bed2e3f741e" = true # a number and a word whitespace separated is invalid "46c8dd65-0c32-4273-bb0d-f2b111bccfbd" = true ================================================ FILE: exercises/practice/binary/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/binary/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/binary/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/binary/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/binary/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/binary/src/main/kotlin/Binary.kt ================================================ object Binary { fun toDecimal(s: String): Int { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/binary/src/test/kotlin/BinaryTest.kt ================================================ import org.junit.Test import org.junit.Ignore import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals @RunWith(Parameterized::class) class BinaryTest(val input: String, val expectedOutput: Int) { companion object { @JvmStatic @Parameterized.Parameters(name = "{index}: binary({0})={1}") fun data() = listOf( arrayOf("1", 1), arrayOf("10", 2), arrayOf("11", 3), arrayOf("100", 4), arrayOf("1001", 9), arrayOf("11010", 26), arrayOf("10001101000", 1128), arrayOf("2", 0), arrayOf("5", 0), arrayOf("9", 0), arrayOf("134678", 0), arrayOf("abc10z", 0), arrayOf("011", 3), arrayOf("g1", 0) ) } @Test fun binaryStringToInt() { assertEquals(expectedOutput, Binary.toDecimal(input)) } } ================================================ FILE: exercises/practice/binary-search/.docs/instructions.md ================================================ # Instructions Your task is to implement a binary search algorithm. A binary search algorithm finds an item in a list by repeatedly splitting it in half, only keeping the half which contains the item we're looking for. It allows us to quickly narrow down the possible locations of our item until we find it, or until we've eliminated all possible locations. ~~~~exercism/caution Binary search only works when a list has been sorted. ~~~~ The algorithm looks like this: - Find the middle element of a _sorted_ list and compare it with the item we're looking for. - If the middle element is our item, then we're done! - If the middle element is greater than our item, we can eliminate that element and all the elements **after** it. - If the middle element is less than our item, we can eliminate that element and all the elements **before** it. - If every element of the list has been eliminated then the item is not in the list. - Otherwise, repeat the process on the part of the list that has not been eliminated. Here's an example: Let's say we're looking for the number 23 in the following sorted list: `[4, 8, 12, 16, 23, 28, 32]`. - We start by comparing 23 with the middle element, 16. - Since 23 is greater than 16, we can eliminate the left half of the list, leaving us with `[23, 28, 32]`. - We then compare 23 with the new middle element, 28. - Since 23 is less than 28, we can eliminate the right half of the list: `[23]`. - We've found our item. ================================================ FILE: exercises/practice/binary-search/.docs/introduction.md ================================================ # Introduction You have stumbled upon a group of mathematicians who are also singer-songwriters. They have written a song for each of their favorite numbers, and, as you can imagine, they have a lot of favorite numbers (like [0][zero] or [73][seventy-three] or [6174][kaprekars-constant]). You are curious to hear the song for your favorite number, but with so many songs to wade through, finding the right song could take a while. Fortunately, they have organized their songs in a playlist sorted by the title — which is simply the number that the song is about. You realize that you can use a binary search algorithm to quickly find a song given the title. [zero]: https://en.wikipedia.org/wiki/0 [seventy-three]: https://en.wikipedia.org/wiki/73_(number) [kaprekars-constant]: https://en.wikipedia.org/wiki/6174_(number) ================================================ FILE: exercises/practice/binary-search/.meta/config.json ================================================ { "authors": [ "geoand" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/BinarySearch.kt" ], "test": [ "src/test/kotlin/BinarySearchTest.kt" ], "example": [ ".meta/src/reference/kotlin/BinarySearch.kt" ] }, "blurb": "Implement a binary search algorithm.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Binary_search_algorithm" } ================================================ FILE: exercises/practice/binary-search/.meta/src/reference/kotlin/BinarySearch.kt ================================================ object BinarySearch { fun > search(list: List, item: T) : Int { require(list.isSorted()) {"The provided list must be sorted in ascending order"} if(list.isEmpty()) { throw NoSuchElementException("value $item is not in array $list") } return searchRec(list, item, 0) } private tailrec fun > searchRec(list: List, item: T, accumulatedOffset: Int) : Int { if(1 == list.size) { return if(list.first() == item) accumulatedOffset else throw NoSuchElementException("value $item is not in array $list") } val midIndex = list.size / 2 val midValue = list[midIndex] if(item < midValue) { return searchRec(list.subList(0, midIndex), item, accumulatedOffset) } return searchRec(list.subList(midIndex, list.size), item, midIndex + accumulatedOffset) } /** * The following extension methods are more general, in a project they would probably not be private */ /** * Uses a sequence of Pair objects in order to avoid calculating all the pairs beforehand in cases * where the list is not sorted */ private fun > List.isSorted(): Boolean { if(this.isEmpty()) { return true } return this.pairsSequence().all { it.first <= it.second } } /** * Returns a sequence of Pair objects containing all each object of the list plus it's following object */ private fun List.pairsSequence() : Sequence> { if(this.size < 2) { return emptySequence() } val list = this return object : Sequence> { override fun iterator(): Iterator> { return object: AbstractIterator>() { var index = 0 override fun computeNext() { if(index >= (list.size-1)) { done() } else { setNext(Pair(list[index], list[index+1])) index += 1 } } } } } } } ================================================ FILE: exercises/practice/binary-search/.meta/tests.toml ================================================ [canonical-tests] # finds a value in an array with one element "b55c24a9-a98d-4379-a08c-2adcf8ebeee8" = true # finds a value in the middle of an array "73469346-b0a0-4011-89bf-989e443d503d" = true # finds a value at the beginning of an array "327bc482-ab85-424e-a724-fb4658e66ddb" = true # finds a value at the end of an array "f9f94b16-fe5e-472c-85ea-c513804c7d59" = true # finds a value in an array of odd length "f0068905-26e3-4342-856d-ad153cadb338" = true # finds a value in an array of even length "fc316b12-c8b3-4f5e-9e89-532b3389de8c" = true # identifies that a value is not included in the array "da7db20a-354f-49f7-a6a1-650a54998aa6" = true # a value smaller than the array's smallest value is not found "95d869ff-3daf-4c79-b622-6e805c675f97" = true # a value larger than the array's largest value is not found "8b24ef45-6e51-4a94-9eac-c2bf38fdb0ba" = true # nothing is found in an empty array "f439a0fa-cf42-4262-8ad1-64bf41ce566a" = true # nothing is found when the left and right bounds cross "2c353967-b56d-40b8-acff-ce43115eed64" = true ================================================ FILE: exercises/practice/binary-search/.meta/version ================================================ 1.3.0 ================================================ FILE: exercises/practice/binary-search/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/binary-search/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/binary-search/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/binary-search/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/binary-search/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/binary-search/src/main/kotlin/BinarySearch.kt ================================================ object BinarySearch { fun search(list: List, item: Int): Int { TODO("Implement the function to complete the task. Change the signature if necessary.") } } ================================================ FILE: exercises/practice/binary-search/src/test/kotlin/BinarySearchTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class BinarySearchTest { @Test fun `finds value in array with one element`() = assertEquals(0, BinarySearch.search(listOf(6), 6)) @Ignore @Test fun `finds value in the middle of array`() = assertEquals(3, BinarySearch.search(listOf(1, 3, 4, 6, 8, 9, 11), 6)) @Ignore @Test fun `finds value at the beginning of array`() = assertEquals(0, BinarySearch.search(listOf(1, 3, 4, 6, 8, 9, 11), 1)) @Ignore @Test fun `finds value at the end of array`() = assertEquals(6, BinarySearch.search(listOf(1, 3, 4, 6, 8, 9, 11), 11)) @Ignore @Test fun `finds value in array of odd length`() = assertEquals(9, BinarySearch.search(listOf(1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634), 144)) @Ignore @Test fun `finds value in array of even length`() = assertEquals(5, BinarySearch.search(listOf(1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377), 21)) @Ignore @Test(expected = NoSuchElementException::class) fun `identifies that value is not included in array`() { BinarySearch.search(listOf(1, 3, 4, 6, 8, 9, 11), 7) } @Ignore @Test(expected = NoSuchElementException::class) fun `value smaller than array's smallest value is not found`() { BinarySearch.search(listOf(1, 3, 4, 6, 8, 9, 11), 0) } @Ignore @Test(expected = NoSuchElementException::class) fun `value larger than array's largest value is not found`() { BinarySearch.search(listOf(1, 3, 4, 6, 8, 9, 11), 13) } @Ignore @Test(expected = NoSuchElementException::class) fun `nothing is found in empty array`() { BinarySearch.search(emptyList(), 1) } @Ignore @Test(expected = NoSuchElementException::class) fun `nothing is found when left and right bounds cross`() { BinarySearch.search(listOf(1, 2), 0) } } ================================================ FILE: exercises/practice/binary-search-tree/.docs/instructions.md ================================================ # Instructions Insert and search for numbers in a binary tree. When we need to represent sorted data, an array does not make a good data structure. Say we have the array `[1, 3, 4, 5]`, and we add 2 to it so it becomes `[1, 3, 4, 5, 2]`. Now we must sort the entire array again! We can improve on this by realizing that we only need to make space for the new item `[1, nil, 3, 4, 5]`, and then adding the item in the space we added. But this still requires us to shift many elements down by one. Binary Search Trees, however, can operate on sorted data much more efficiently. A binary search tree consists of a series of connected nodes. Each node contains a piece of data (e.g. the number 3), a variable named `left`, and a variable named `right`. The `left` and `right` variables point at `nil`, or other nodes. Since these other nodes in turn have other nodes beneath them, we say that the left and right variables are pointing at subtrees. All data in the left subtree is less than or equal to the current node's data, and all data in the right subtree is greater than the current node's data. For example, if we had a node containing the data 4, and we added the data 2, our tree would look like this: 4 / 2 If we then added 6, it would look like this: 4 / \ 2 6 If we then added 3, it would look like this 4 / \ 2 6 \ 3 And if we then added 1, 5, and 7, it would look like this 4 / \ / \ 2 6 / \ / \ 1 3 5 7 ================================================ FILE: exercises/practice/binary-search-tree/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "glennj", "uzilan" ], "files": { "solution": [ "src/main/kotlin/BinarySearchTree.kt" ], "test": [ "src/test/kotlin/BinarySearchTreeTest.kt" ], "example": [ ".meta/src/reference/kotlin/BinarySearchTree.kt" ] }, "blurb": "Insert and search for numbers in a binary tree.", "source": "Josh Cheek" } ================================================ FILE: exercises/practice/binary-search-tree/.meta/src/reference/kotlin/BinarySearchTree.kt ================================================ class BinarySearchTree> { data class Node(val data: T, var left: Node? = null, var right: Node? = null) var root: Node? = null fun insert(value: T) { if (root == null) { root = Node(value) } else { insert(value, root!!) } } private fun insert(value: T, parent: Node) { if (value > parent.data) { if (parent.right == null) { parent.right = Node(value) } else { insert(value, parent.right!!) } } else { // Equal elements are inserted on the left side, too! if (parent.left == null) { parent.left = Node(value) } else { insert(value, parent.left!!) } } } fun asSortedList(): List { return asSortedList(root).map { it.data } } private fun asSortedList(start: Node?): List> = if (start == null) { emptyList() } else { asSortedList(start.left) + listOf(start) + asSortedList(start.right) } fun asLevelOrderList(): List = if (root == null) { emptyList() } else { asLevelOrderList(listOf(), listOf(root!!)).first.map { it.data } } private fun asLevelOrderList(done: List>, todo: List>): Pair>, List>> { if (todo.isEmpty()) { return Pair(done, emptyList()) } return asLevelOrderList( done + todo, todo.flatMap { listOfNotNull(it.left, it.right) }) } } ================================================ FILE: exercises/practice/binary-search-tree/.meta/tests.toml ================================================ [canonical-tests] # data is retained "e9c93a78-c536-4750-a336-94583d23fafa" = true # smaller number at left node "7a95c9e8-69f6-476a-b0c4-4170cb3f7c91" = true # same number at left node "22b89499-9805-4703-a159-1a6e434c1585" = true # greater number at right node "2e85fdde-77b1-41ed-b6ac-26ce6b663e34" = true # can create complex tree "dd898658-40ab-41d0-965e-7f145bf66e0b" = true # can sort single number "9e0c06ef-aeca-4202-b8e4-97f1ed057d56" = true # can sort if second number is smaller than first "425e6d07-fceb-4681-a4f4-e46920e380bb" = true # can sort if second number is same as first "bd7532cc-6988-4259-bac8-1d50140079ab" = true # can sort if second number is greater than first "b6d1b3a5-9d79-44fd-9013-c83ca92ddd36" = true # can sort complex tree "d00ec9bd-1288-4171-b968-d44d0808c1c8" = true ================================================ FILE: exercises/practice/binary-search-tree/.meta/version ================================================ 1.0.0 ================================================ FILE: exercises/practice/binary-search-tree/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/binary-search-tree/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/binary-search-tree/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/binary-search-tree/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/binary-search-tree/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/binary-search-tree/src/main/kotlin/BinarySearchTree.kt ================================================ class BinarySearchTree> { data class Node(val data: T /* maybe more... */) var root: Node? = null fun insert(value: T) { TODO("Delete this statement and write your own implementation.") } fun asSortedList(): List { TODO("Delete this statement and write your own implementation.") } fun asLevelOrderList(): List { TODO("Delete this statement and write your own implementation.") } } ================================================ FILE: exercises/practice/binary-search-tree/src/test/kotlin/BinarySearchTreeTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull class BinarySearchTreeTest { @Test fun `data is retained`() { val tree = BinarySearchTree() val expected = 4 tree.insert(expected) val root = tree.root assertNotNull(root) val actual = root.data assertEquals(expected, actual) } @Ignore @Test fun `inserts less`() { val tree = BinarySearchTree() val expectedRoot = '4' val expectedLeft = '2' tree.insert(expectedRoot) tree.insert(expectedLeft) val root = tree.root assertNotNull(root) val left = root.left assertNotNull(left) val actualRoot = root.data val actualLeft = left.data assertEquals(expectedLeft, actualLeft) assertEquals(expectedRoot, actualRoot) } @Ignore @Test fun `inserts same`() { val tree = BinarySearchTree() val expectedRoot = "4" val expectedLeft = "4" tree.insert(expectedRoot) tree.insert(expectedLeft) val root = tree.root assertNotNull(root) val left = root.left assertNotNull(left) val actualRoot = root.data val actualLeft = left.data assertEquals(expectedLeft, actualLeft) assertEquals(expectedRoot, actualRoot) } @Ignore @Test fun `inserts right`() { val tree = BinarySearchTree() val expectedRoot = 4 val expectedRight = 5 tree.insert(expectedRoot) tree.insert(expectedRight) val root = tree.root assertNotNull(root) val right = root.right assertNotNull(right) val actualRoot = root.data val actualRight = right.data assertEquals(expectedRight, actualRight) assertEquals(expectedRoot, actualRoot) } @Ignore @Test fun `creates complex tree`() { val tree = BinarySearchTree() val expected = listOf('4', '2', '6', '1', '3', '5', '7') val treeData = listOf('4', '2', '6', '1', '3', '5', '7') treeData.forEach(tree::insert) val actual = tree.asLevelOrderList() assertEquals(expected, actual) } @Ignore @Test fun `sorts single element`() { val tree = BinarySearchTree() val expected = listOf("2") tree.insert("2") val actual = tree.asSortedList() assertEquals(expected, actual) } @Ignore @Test fun `sorts collection of two if second inserted is smaller than first`() { val tree = BinarySearchTree() val expected: List = listOf(1, 2) tree.insert(2) tree.insert(1) val actual = tree.asSortedList() assertEquals(expected, actual) } @Ignore @Test fun `sorts collection of two if second number is same as first`() { val tree = BinarySearchTree() val expected = listOf('2', '2') tree.insert('2') tree.insert('2') val actual = tree.asSortedList() assertEquals(expected, actual) } @Ignore @Test fun `sorts collection of two if second inserted is bigger than first`() { val tree = BinarySearchTree() val expected = listOf('2', '3') tree.insert('2') tree.insert('3') val actual = tree.asSortedList() assertEquals(expected, actual) } @Ignore @Test fun `iterates over complex tree`() { val tree = BinarySearchTree() val expected = listOf("1", "2", "3", "5", "6", "7") val treeData = listOf("2", "1", "3", "6", "7", "5") treeData.forEach(tree::insert) val actual = tree.asSortedList() assertEquals(expected, actual) } @Ignore @Test fun `big tree level order`() { val tree = BinarySearchTree() val expected = listOf(8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15) val treeData = listOf(8, 4, 2, 6, 1, 3, 5, 7, 12, 14, 10, 9, 11, 13, 15) treeData.forEach(tree::insert) val actual = tree.asLevelOrderList() assertEquals(expected, actual) } } ================================================ FILE: exercises/practice/bob/.approaches/answer-list/content.md ================================================ # Answer `List` ```kotlin object Bob { private val answers = listOf("Whatever.", "Sure.", "Whoa, chill out!", "Calm down, I know what I'm doing!") fun hey(input: String): String { val msg = input.trim() if (msg.isEmpty()) return "Fine. Be that way!" val isQuestion = if (msg.endsWith('?')) 1 else 0 val isYelling = if (('A'..'Z').any { msg.contains(it) } && msg == msg.uppercase()) 2 else 0 return answers[isQuestion + isYelling] } } ``` In this approach you define a `List` that contains Bob’s answers, and each condition is given a score. The correct answer is selected from the `List` by using the score as the `List` index. An [object declaration][object] is used to define `Bob` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `hey` method. The [`listOf`][listof] method is used to create a list of Bob's answers. The `String` [`trim()`][trim] method is applied to the input to eliminate any whitespace at either end of the input. If the string has no characters left, it returns the response for saying nothing. ~~~~exercism/caution Note that a `null` `string` would be different from a `String` of all whitespace. A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it. ~~~~ A question is determined by use of the [`endsWith()`][endswith] method to see if the input ends with a question mark. A [range][range] of `A..Z` is defined to look for uppercase English alphabetic characters. The first half of the `isYelling` implementation ```java if (('A'..'Z').any { msg.contains(it) } ``` is constructed from the range and the [`any`][any] method to ensure there is at least one uppercase letter character in the `String`. The [lambda][lambda] of `any` uses the [`it`][it] keyword to refer to the single `Char` parameter for the lambda, and passes it to the [`contains`][contains] method to check if the character is in the input `String`. The check that there is any alphabetic character is needed, because the second half of the condition tests that the uppercased input is the same as the input. If the input were only `"123"` it would equal itself uppercased, but without letters it would not be a yell. The conditions of being a question and being a yell are assigned scores through the use of the [ternary expression][ternary-expression]. For example, giving a question a score of `1` would use an index of `1` to get the element from the answers `List`, which is `"Sure."`. | isYelling | isQuestion | Index | Answer | | --------- | ---------- | --------- | ------------------------------------- | | `false` | `false` | 0 + 0 = 0 | `"Whatever."` | | `false` | `true` | 0 + 1 = 1 | `"Sure."` | | `true` | `false` | 2 + 0 = 2 | `"Whoa, chill out!"` | | `true` | `true` | 2 + 1 = 3 | `"Calm down, I know what I'm doing!"` | [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [listof]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html [trim]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim.html [endswith]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/ends-with.html [range]: https://kotlinlang.org/docs/ranges.html#range [any]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/any.html [contains]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/contains.html [ternary-expression]: https://kotlinlang.org/docs/control-flow.html#if-expression [lambda]: https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions [it]: https://kotlinlang.org/docs/lambdas.html#it-implicit-name-of-a-single-parameter ================================================ FILE: exercises/practice/bob/.approaches/answer-list/snippet.txt ================================================ fun hey(input: String): String { val msg = input.trim() if (msg.isEmpty()) return "Fine. Be that way!" val isQuestion = if (msg.endsWith('?')) 1 else 0 val isYelling = if (('A'..'Z').any { msg.contains(it) } && msg == msg.uppercase()) 2 else 0 return answers[isQuestion + isYelling] } ================================================ FILE: exercises/practice/bob/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "51d03dc6-c93e-4d49-88b5-89165f00c1d8", "slug": "if-expressions", "title": "if expressions", "blurb": "Use if expressions to return the answer.", "authors": [ "bobahop" ] }, { "uuid": "1cd79ba8-6786-4ae4-a248-0f89a1daa8a8", "slug": "answer-list", "title": "Answer List", "blurb": "Index into a List to return the answer.", "authors": [ "bobahop" ] }, { "uuid": "7aebc1df-c23a-42c9-90c4-f022e40d67e9", "slug": "when-expression", "title": "when expression", "blurb": "Use a when expression to return the answer.", "authors": [ "micha-b" ] } ] } ================================================ FILE: exercises/practice/bob/.approaches/if-expressions/content.md ================================================ # `if` expressions ```kotlin object Bob { fun hey(input: String): String { val msg = input.trim() if (msg.isEmpty()) return "Fine. Be that way!" val isQuestion = msg.endsWith('?') val isYelling = ('A'..'Z').any { msg.contains(it) } && msg == msg.uppercase() if (isYelling) return if (isQuestion) "Calm down, I know what I'm doing!" else "Whoa, chill out!" else return if (isQuestion) "Sure." else "Whatever." } } ``` In this approach you have a series of `if` expressions to evaluate the conditions. As soon as the right condition is found, the correct response is returned. An [object declaration][object] is used to define `Bob` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `hey` method. The `String` [`trim()`][trim] method is applied to the input to eliminate any whitespace at either end of the input. If the string has no characters left, it returns the response for saying nothing. ~~~~exercism/caution Note that a `null` `string` would be different from a `String` of all whitespace. A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it. ~~~~ A question is determined by use of the [`endsWith()`][endswith] method to see if the input ends with a question mark. A [range][range] of `A..Z` is defined to look for uppercase English alphabetic characters. The first half of the `isYelling` implementation ```java if (('A'..'Z').any { msg.contains(it) } ``` is constructed from the range and the [`any`][any] method to ensure there is at least one uppercase letter character in the `String`. The [lambda][lambda] of `any` uses the [`it`][it] keyword to refer to the single `Char` parameter for the lambda, and passes it to the [`contains`][contains] method to check if the character is in the input `String`. The check that there is any alphabetic character is needed, because the second half of the condition tests that the uppercased input is the same as the input. If the input were only `"123"` it would equal itself uppercased, but without letters it would not be a yell. If `isYelling` is `true`, then a [ternary expresson][ternary-expression] is used to return either the response for a yelled question or just a yell. If `isYelling` is `false`, then a ternary expression is used to return either the response for a question or a plain statement. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [trim]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim.html [endswith]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/ends-with.html [range]: https://kotlinlang.org/docs/ranges.html#range [any]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/any.html [contains]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/contains.html [ternary-expression]: https://kotlinlang.org/docs/control-flow.html#if-expression [lambda]: https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions [it]: https://kotlinlang.org/docs/lambdas.html#it-implicit-name-of-a-single-parameter ================================================ FILE: exercises/practice/bob/.approaches/if-expressions/snippet.txt ================================================ fun hey(input: String): String { val msg = input.trim() if (msg.isEmpty()) return "Fine. Be that way!" val isQuestion = msg.endsWith('?') val isYelling = ('A'..'Z').any { msg.contains(it) } && msg == msg.uppercase() if (isYelling) return if (isQuestion) "Calm down, I know what I'm doing!" else "Whoa, chill out!" else return if (isQuestion) "Sure." else "Whatever." ================================================ FILE: exercises/practice/bob/.approaches/introduction.md ================================================ # Introduction There are various idiomatic approaches to solve Bob. A basic approach can use a series of `if` expressions to test the conditions. A `List` can contain answers from which the right response is selected by an index calculated from scores given to the conditions. ## General guidance Regardless of the approach used, some things you could look out for include - If the input is trimmed, [`trim()`][trim] only once. - Use the [`endsWith()`][endswith] method instead of checking the last character by index for `?`. - Don't copy/paste the logic for determining a shout and for determining a question into determining a shouted question. Combine the two determinations instead of copying them. Not duplicating the code will keep the code [DRY][dry]. - Perhaps consider making `questioning` and `shouting` values set once instead of functions that are possibly called more than once. ## Approach: `if` expressions ```kotlin object Bob { fun hey(input: String): String { val msg = input.trim() if (msg.isEmpty()) return "Fine. Be that way!" val isQuestion = msg.endsWith('?') val isYelling = ('A'..'Z').any { msg.contains(it) } && msg == msg.uppercase() if (isYelling) return if (isQuestion) "Calm down, I know what I'm doing!" else "Whoa, chill out!" else return if (isQuestion) "Sure." else "Whatever." } } ``` For more information, check the [`if` expressions approach][approach-if]. ## Approach: Answer `List` ```kotlin object Bob { private val answers = listOf("Whatever.", "Sure.", "Whoa, chill out!", "Calm down, I know what I'm doing!") fun hey(input: String): String { val msg = input.trim() if (msg.isEmpty()) return "Fine. Be that way!" val isQuestion = if (msg.endsWith('?')) 1 else 0 val isYelling = if (('A'..'Z').any { msg.contains(it) } && msg == msg.uppercase()) 2 else 0 return answers[isQuestion + isYelling] } } ``` For more information, check the [Answer `List` approach][approach-answer-list]. ## Approach: `when` expression ```kotlin object Bob { fun hey(statement: String): String = when { statement.isQuestion() && statement.isYelling() -> "Calm down, I know what I'm doing!" statement.isQuestion() -> "Sure." statement.isYelling() -> "Whoa, chill out!" statement.isSilence() -> "Fine. Be that way!" else -> "Whatever." } } ``` For more information, check the [`when` expression approach][approach-when] ## Which approach to use? The choice between `if` expressions and answers `List` can be made by perceived readability. [trim]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim.html [endswith]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/ends-with.html [dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself [approach-if]: https://exercism.org/tracks/kotlin/exercises/bob/approaches/if-expressions [approach-answer-list]: https://exercism.org/tracks/kotlin/exercises/bob/approaches/answer-list [approach-when]: https://exercism.org/tracks/kotlin/exercises/bob/approaches/when-expression ================================================ FILE: exercises/practice/bob/.approaches/when-expression/content.md ================================================ # `when` expressions ```kotlin object Bob { fun hey(statement: String): String = when { statement.isQuestion() && statement.isYelling() -> "Calm down, I know what I'm doing!" statement.isQuestion() -> "Sure." statement.isYelling() -> "Whoa, chill out!" statement.isSilence() -> "Fine. Be that way!" else -> "Whatever." } private fun String.isSilence(): Boolean = this.isBlank() private fun String.isQuestion(): Boolean = this.trim().endsWith('?') private fun String.isYelling(): Boolean = any(Char::isLetter) && toUpperCase() == this } ``` In this approach you have a `when` expression containing different so-called branches that can be matched using the corresponding patterns. As soon as one of these patterns on the left side of the arrow (`->`) is matched ... 1. the value on the right side 2. the block on the right side is executed and the value retuned from the block ... is returned from the `when` expression. Only one branch is matched in one execution of the `when` expression. The branches are matched from top to bottom and the first branch in which the condition evaluates to `true` is selected. If none of the given conditions matches the `else` branch is selected and returned. ~~~~exercism/caution Depending on what patterns are on the left side of your branches the order of branches is important to the correct execution of the `when` expression since the first matching branch is selected. ~~~~ An [object declaration][object] is used to define `Bob` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `hey` method. Inside this object there are some `private` [extension methods as members][extension-members] of the `object`. This adds these methods to the `String` data type for `private` usage of these methods in this `object`. This allows calling the methods directly on the `String` instead of passing the `String` to the method. (More about extension methods in general [here][extension-general]) These extension methods check for: 1. `isSilence()`: a blank string 2. `isQuestion()`: a string with the last non-whitespace-character being a question mark 3. `isYelling()`: a string with all letters in uppercase When combining these methods as in the `when` expression above you can map all the cases required by the exercise. [when]: https://kotlinlang.org/docs/control-flow.html#when-expression [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [extension-members]: https://kotlinlang.org/docs/extensions.html#declaring-extensions-as-members [extension-general]: https://kotlinlang.org/docs/extensions.html ================================================ FILE: exercises/practice/bob/.approaches/when-expression/snippet.txt ================================================ fun hey(statement: String): String = when { statement.isQuestion() && statement.isYelling() -> "Calm down, I know what I'm doing!" statement.isQuestion() -> "Sure." statement.isYelling() -> "Whoa, chill out!" statement.isSilence() -> "Fine. Be that way!" else -> "Whatever." } ================================================ FILE: exercises/practice/bob/.docs/instructions.md ================================================ # Instructions Your task is to determine what Bob will reply to someone when they say something to him or ask him a question. Bob only ever answers one of five things: - **"Sure."** This is his response if you ask him a question, such as "How are you?" The convention used for questions is that it ends with a question mark. - **"Whoa, chill out!"** This is his answer if you YELL AT HIM. The convention used for yelling is ALL CAPITAL LETTERS. - **"Calm down, I know what I'm doing!"** This is what he says if you yell a question at him. - **"Fine. Be that way!"** This is how he responds to silence. The convention used for silence is nothing, or various combinations of whitespace characters. - **"Whatever."** This is what he answers to anything else. ================================================ FILE: exercises/practice/bob/.docs/introduction.md ================================================ # Introduction Bob is a [lackadaisical][] teenager. He likes to think that he's very cool. And he definitely doesn't get excited about things. That wouldn't be cool. When people talk to him, his responses are pretty limited. [lackadaisical]: https://www.collinsdictionary.com/dictionary/english/lackadaisical ================================================ FILE: exercises/practice/bob/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Bob.kt" ], "test": [ "src/test/kotlin/BobTest.kt" ], "example": [ ".meta/src/reference/kotlin/Bob.kt" ] }, "blurb": "Bob is a lackadaisical teenager. In conversation, his responses are very limited.", "source": "Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial.", "source_url": "https://pine.fm/LearnToProgram/?Chapter=06" } ================================================ FILE: exercises/practice/bob/.meta/src/reference/kotlin/Bob.kt ================================================ object Bob { fun hey(input: String): String { val trimmedInput = input.trim() return when { isSilence(trimmedInput) -> "Fine. Be that way!" isShoutedQuestion(trimmedInput) -> "Calm down, I know what I'm doing!" isShout(trimmedInput) -> "Whoa, chill out!" isQuestion(trimmedInput) -> "Sure." else -> "Whatever." } } private fun isSilence(input: String) = input.isBlank() private fun isQuestion(input: String) = input.endsWith("?") private fun isShout(input: String): Boolean { val isOnlyUppercase = input == input.uppercase() val hasLetter = input.contains(Regex("[A-Z]")) return hasLetter && isOnlyUppercase } private fun isShoutedQuestion(input: String) = isShout(input) && isQuestion(input) } ================================================ FILE: exercises/practice/bob/.meta/tests.toml ================================================ [canonical-tests] # stating something "e162fead-606f-437a-a166-d051915cea8e" = true # shouting "73a966dc-8017-47d6-bb32-cf07d1a5fcd9" = true # shouting gibberish "d6c98afd-df35-4806-b55e-2c457c3ab748" = true # asking a question "8a2e771d-d6f1-4e3f-b6c6-b41495556e37" = true # asking a numeric question "81080c62-4e4d-4066-b30a-48d8d76920d9" = true # asking gibberish "2a02716d-685b-4e2e-a804-2adaf281c01e" = true # talking forcefully "c02f9179-ab16-4aa7-a8dc-940145c385f7" = true # using acronyms in regular speech "153c0e25-9bb5-4ec5-966e-598463658bcd" = true # forceful question "a5193c61-4a92-4f68-93e2-f554eb385ec6" = true # shouting numbers "a20e0c54-2224-4dde-8b10-bd2cdd4f61bc" = true # no letters "f7bc4b92-bdff-421e-a238-ae97f230ccac" = true # question with no letters "bb0011c5-cd52-4a5b-8bfb-a87b6283b0e2" = true # shouting with special characters "496143c8-1c31-4c01-8a08-88427af85c66" = true # shouting with no exclamation mark "e6793c1c-43bd-4b8d-bc11-499aea73925f" = true # statement containing question mark "aa8097cc-c548-4951-8856-14a404dd236a" = true # non-letters with question "9bfc677d-ea3a-45f2-be44-35bc8fa3753e" = true # prattling on "8608c508-f7de-4b17-985b-811878b3cf45" = true # silence "bc39f7c6-f543-41be-9a43-fd1c2f753fc0" = true # prolonged silence "d6c47565-372b-4b09-b1dd-c40552b8378b" = true # alternate silence "4428f28d-4100-4d85-a902-e5a78cb0ecd3" = true # multiple line question "66953780-165b-4e7e-8ce3-4bcb80b6385a" = true # starting with whitespace "5371ef75-d9ea-4103-bcfa-2da973ddec1b" = true # ending with whitespace "05b304d6-f83b-46e7-81e0-4cd3ca647900" = true # other whitespace "72bd5ad3-9b2f-4931-a988-dce1f5771de2" = true # non-question ending with whitespace "12983553-8601-46a8-92fa-fcaa3bc4a2a0" = true ================================================ FILE: exercises/practice/bob/.meta/version ================================================ 1.4.0 ================================================ FILE: exercises/practice/bob/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/bob/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/bob/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/bob/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/bob/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/bob/src/main/kotlin/Bob.kt ================================================ object Bob { fun hey(input: String): String { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/bob/src/test/kotlin/BobTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class BobTest { @Test fun statingSomething() { assertEquals("Whatever.", Bob.hey("Tom-ay-to, tom-aaaah-to.")) } @Ignore @Test fun shouting() { assertEquals("Whoa, chill out!", Bob.hey("WATCH OUT!")) } @Ignore @Test fun shoutingGibberish() { assertEquals("Whoa, chill out!", Bob.hey("FCECDFCAAB")) } @Ignore @Test fun askingAQuestion() { assertEquals("Sure.", Bob.hey("Does this cryogenic chamber make me look fat?")) } @Ignore @Test fun askingANumericQuestion() { assertEquals("Sure.", Bob.hey("You are, what, like 15?")) } @Ignore @Test fun askingGibberish() { assertEquals("Sure.", Bob.hey("fffbbcbeab?")) } @Ignore @Test fun talkingForcefully() { assertEquals("Whatever.", Bob.hey("Let's go make out behind the gym!")) } @Ignore @Test fun usingAcronymsInRegularSpeech() { assertEquals("Whatever.", Bob.hey("It's OK if you don't want to go to the DMV.")) } @Ignore @Test fun forcefulQuestion() { assertEquals("Calm down, I know what I'm doing!", Bob.hey("WHAT THE HELL WERE YOU THINKING?")) } @Ignore @Test fun shoutingNumbers() { assertEquals("Whoa, chill out!", Bob.hey("1, 2, 3 GO!")) } @Ignore @Test fun noLetters() { assertEquals("Whatever.", Bob.hey("1, 2, 3")) } @Ignore @Test fun questionWithNoLetters() { assertEquals("Sure.", Bob.hey("4?")) } @Ignore @Test fun shoutingWithSpecialCharacters() { assertEquals("Whoa, chill out!", Bob.hey("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!")) } @Ignore @Test fun shoutingWithNoExclamationMark() { assertEquals("Whoa, chill out!", Bob.hey("I HATE THE DMV")) } @Ignore @Test fun statementContainingQuestionMark() { assertEquals("Whatever.", Bob.hey("Ending with ? means a question.")) } @Ignore @Test fun nonLettersWithQuestion() { assertEquals("Sure.", Bob.hey(":) ?")) } @Ignore @Test fun prattlingOn() { assertEquals("Sure.", Bob.hey("Wait! Hang on. Are you going to be OK?")) } @Ignore @Test fun silence() { assertEquals("Fine. Be that way!", Bob.hey("")) } @Ignore @Test fun prolongedSilence() { assertEquals("Fine. Be that way!", Bob.hey(" ")) } @Ignore @Test fun alternateSilence() { assertEquals("Fine. Be that way!", Bob.hey("\t\t\t\t\t\t\t\t\t\t")) } @Ignore @Test fun multipleLineQuestion() { assertEquals("Whatever.", Bob.hey("\nDoes this cryogenic chamber make me look fat?\nno")) } @Ignore @Test fun startingWithWhitespace() { assertEquals("Whatever.", Bob.hey(" hmmmmmmm...")) } @Ignore @Test fun endingWithWhitespace() { assertEquals("Sure.", Bob.hey("Okay if like my spacebar quite a bit? ")) } @Ignore @Test fun otherWhitespace() { assertEquals("Fine. Be that way!", Bob.hey("\n\r \t")) } @Ignore @Test fun nonQuestionEndingWithWhitespace() { assertEquals("Whatever.", Bob.hey("This is a statement ending with whitespace ")) } } ================================================ FILE: exercises/practice/bottle-song/.docs/instructions.md ================================================ # Instructions Recite the lyrics to that popular children's repetitive song: Ten Green Bottles. Note that not all verses are identical. ```text Ten green bottles hanging on the wall, Ten green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be nine green bottles hanging on the wall. Nine green bottles hanging on the wall, Nine green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be eight green bottles hanging on the wall. Eight green bottles hanging on the wall, Eight green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be seven green bottles hanging on the wall. Seven green bottles hanging on the wall, Seven green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be six green bottles hanging on the wall. Six green bottles hanging on the wall, Six green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be five green bottles hanging on the wall. Five green bottles hanging on the wall, Five green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be four green bottles hanging on the wall. Four green bottles hanging on the wall, Four green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be three green bottles hanging on the wall. Three green bottles hanging on the wall, Three green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be two green bottles hanging on the wall. Two green bottles hanging on the wall, Two green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be one green bottle hanging on the wall. One green bottle hanging on the wall, One green bottle hanging on the wall, And if one green bottle should accidentally fall, There'll be no green bottles hanging on the wall. ``` ================================================ FILE: exercises/practice/bottle-song/.meta/config.json ================================================ { "authors": [ "kahgoh" ], "files": { "solution": [ "src/main/kotlin/BottleSong.kt" ], "test": [ "src/test/kotlin/BottleSongTest.kt" ], "example": [ ".meta/src/reference/kotlin/BottleSong.kt" ] }, "blurb": "Produce the lyrics to the popular children's repetitive song: Ten Green Bottles.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Ten_Green_Bottles" } ================================================ FILE: exercises/practice/bottle-song/.meta/src/reference/kotlin/BottleSong.kt ================================================ object BottleSong { fun recite(startBottles : Int, takeDown : Int) : String { return (0..(takeDown - 1)) .joinToString(separator = "\n\n") { verse(startBottles - it) } } private fun verse(bottles : Int) : String { val start = verseStart(bottles) return """ $start $start And if one green bottle should accidentally fall, ${verseEnd(bottles - 1)} """.trimIndent() } private fun verseStart(bottles : Int) : String { return if (bottles > 1) { "${toWord(bottles)} green bottles hanging on the wall," } else { "One green bottle hanging on the wall," } } private fun verseEnd(bottles : Int) : String { return when(bottles) { 0 -> "There'll be no green bottles hanging on the wall." 1 -> "There'll be ${toWord(bottles).lowercase()} green bottle hanging on the wall." else -> "There'll be ${toWord(bottles).lowercase()} green bottles hanging on the wall." } } private fun toWord(num : Int) : String { return when(num) { 1 -> "One" 2 -> "Two" 3 -> "Three" 4 -> "Four" 5 -> "Five" 6 -> "Six" 7 -> "Seven" 8 -> "Eight" 9 -> "Nine" 10 -> "Ten" else -> throw IllegalArgumentException("Number $num not supported") } } } ================================================ FILE: exercises/practice/bottle-song/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [d4ccf8fc-01dc-48c0-a201-4fbeb30f2d03] description = "verse -> single verse -> first generic verse" [0f0aded3-472a-4c64-b842-18d4f1f5f030] description = "verse -> single verse -> last generic verse" [f61f3c97-131f-459e-b40a-7428f3ed99d9] description = "verse -> single verse -> verse with 2 bottles" [05eadba9-5dbd-401e-a7e8-d17cc9baa8e0] description = "verse -> single verse -> verse with 1 bottle" [a4a28170-83d6-4dc1-bd8b-319b6abb6a80] description = "lyrics -> multiple verses -> first two verses" [3185d438-c5ac-4ce6-bcd3-02c9ff1ed8db] description = "lyrics -> multiple verses -> last three verses" [28c1584a-0e51-4b65-9ae2-fbc0bf4bbb28] description = "lyrics -> multiple verses -> all verses" ================================================ FILE: exercises/practice/bottle-song/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/bottle-song/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/bottle-song/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/bottle-song/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/bottle-song/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/bottle-song/src/main/kotlin/BottleSong.kt ================================================ object BottleSong { fun recite(startBottles : Int, takeDown : Int) : String { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/bottle-song/src/test/kotlin/BottleSongTest.kt ================================================ import org.junit.experimental.runners.Enclosed import org.junit.runner.RunWith import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class BottleSongTest { @Test fun `single verse`() { val expected = """ Ten green bottles hanging on the wall, Ten green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be nine green bottles hanging on the wall. """.trimIndent() assertEquals(expected, BottleSong.recite(10, 1)) } @Ignore @Test fun `last generic verse`() { val expected = """ Three green bottles hanging on the wall, Three green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be two green bottles hanging on the wall. """.trimIndent() assertEquals(expected, BottleSong.recite(3, 1)) } @Ignore @Test fun `verse with 2 bottles`() { val expected = """ Two green bottles hanging on the wall, Two green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be one green bottle hanging on the wall. """.trimIndent() assertEquals( expected, BottleSong.recite(2, 1) ) } @Ignore @Test fun `verse with 1 bottle`() { val expected = """ One green bottle hanging on the wall, One green bottle hanging on the wall, And if one green bottle should accidentally fall, There'll be no green bottles hanging on the wall. """.trimIndent() assertEquals( expected, BottleSong.recite(1, 1) ) } @Ignore @Test fun `multiple verses`() { val expected = """ Ten green bottles hanging on the wall, Ten green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be nine green bottles hanging on the wall. Nine green bottles hanging on the wall, Nine green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be eight green bottles hanging on the wall. """.trimIndent() assertEquals( expected, BottleSong.recite(10, 2) ) } @Ignore @Test fun `last three verses`() { val expected = """ Three green bottles hanging on the wall, Three green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be two green bottles hanging on the wall. Two green bottles hanging on the wall, Two green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be one green bottle hanging on the wall. One green bottle hanging on the wall, One green bottle hanging on the wall, And if one green bottle should accidentally fall, There'll be no green bottles hanging on the wall. """.trimIndent() assertEquals( expected, BottleSong.recite(3, 3) ) } @Ignore @Test fun `all verses`() { val expected = """ Ten green bottles hanging on the wall, Ten green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be nine green bottles hanging on the wall. Nine green bottles hanging on the wall, Nine green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be eight green bottles hanging on the wall. Eight green bottles hanging on the wall, Eight green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be seven green bottles hanging on the wall. Seven green bottles hanging on the wall, Seven green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be six green bottles hanging on the wall. Six green bottles hanging on the wall, Six green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be five green bottles hanging on the wall. Five green bottles hanging on the wall, Five green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be four green bottles hanging on the wall. Four green bottles hanging on the wall, Four green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be three green bottles hanging on the wall. Three green bottles hanging on the wall, Three green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be two green bottles hanging on the wall. Two green bottles hanging on the wall, Two green bottles hanging on the wall, And if one green bottle should accidentally fall, There'll be one green bottle hanging on the wall. One green bottle hanging on the wall, One green bottle hanging on the wall, And if one green bottle should accidentally fall, There'll be no green bottles hanging on the wall. """.trimIndent() assertEquals( expected, BottleSong.recite(10, 10) ) } } ================================================ FILE: exercises/practice/bowling/.docs/instructions.md ================================================ # Instructions Score a bowling game. Bowling is a game where players roll a heavy ball to knock down pins arranged in a triangle. Write code to keep track of the score of a game of bowling. ## Scoring Bowling The game consists of 10 frames. A frame is composed of one or two ball throws with 10 pins standing at frame initialization. There are three cases for the tabulation of a frame. - An open frame is where a score of less than 10 is recorded for the frame. In this case the score for the frame is the number of pins knocked down. - A spare is where all ten pins are knocked down by the second throw. The total value of a spare is 10 plus the number of pins knocked down in their next throw. - A strike is where all ten pins are knocked down by the first throw. The total value of a strike is 10 plus the number of pins knocked down in the next two throws. If a strike is immediately followed by a second strike, then the value of the first strike cannot be determined until the ball is thrown one more time. Here is a three frame example: | Frame 1 | Frame 2 | Frame 3 | | :--------: | :--------: | :--------------: | | X (strike) | 5/ (spare) | 9 0 (open frame) | Frame 1 is (10 + 5 + 5) = 20 Frame 2 is (5 + 5 + 9) = 19 Frame 3 is (9 + 0) = 9 This means the current running total is 48. The tenth frame in the game is a special case. If someone throws a spare or a strike then they get one or two fill balls respectively. Fill balls exist to calculate the total of the 10th frame. Scoring a strike or spare on the fill ball does not give the player more fill balls. The total value of the 10th frame is the total number of pins knocked down. For a tenth frame of X1/ (strike and a spare), the total value is 20. For a tenth frame of XXX (three strikes), the total value is 30. ## Requirements Write code to keep track of the score of a game of bowling. It should support two operations: - `roll(pins : int)` is called each time the player rolls a ball. The argument is the number of pins knocked down. - `score() : int` is called only at the very end of the game. It returns the total score for that game. ================================================ FILE: exercises/practice/bowling/.meta/config.json ================================================ { "authors": [ "vmichalak" ], "files": { "solution": [ "src/main/kotlin/BowlingGame.kt" ], "test": [ "src/test/kotlin/BowlingGameTest.kt" ], "example": [ ".meta/src/reference/kotlin/BowlingGame.kt" ] }, "blurb": "Score a bowling game.", "source": "The Bowling Game Kata from UncleBob", "source_url": "https://web.archive.org/web/20221001111000/http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata" } ================================================ FILE: exercises/practice/bowling/.meta/src/reference/kotlin/BowlingGame.kt ================================================ class BowlingGame { private var builder = Frame.Builder() private val frames = mutableListOf() private val isLastFrame: Boolean get() = frames.size == 11 || (frames.size == 10 && !frames[9].isStrike) private val isGameOver: Boolean get() = when { frames.size < 10 -> false frames.size == 10 -> !frames[9].isSpare frames.size == 11 -> !frames[9].isStrike || !frames[10].isStrike else -> true } fun roll(pins: Int) { if(isGameOver) { throw IllegalStateException("Cannot roll after game is over") } builder.withRoll(pins); if (builder.isComplete) { frames.add(builder.build()); builder = Frame.Builder(); } else if (isLastFrame) { frames.add(builder.build()); } } fun score(): Int { if(!isGameOver) { throw IllegalStateException("Score cannot be taken until the end of the game") } return (0 until 10).sumOf { index -> val current = frames[index] val next = frames.getOrElse(index + 1) { Frame.EMPTY } val nextNext = frames.getOrElse(index + 2) { Frame.EMPTY } current.score(next, nextNext) } } } ================================================ FILE: exercises/practice/bowling/.meta/src/reference/kotlin/Frame.kt ================================================ class Frame(val first: Int, val second: Int) { companion object { val EMPTY = Frame(0, 0) } val frameScore: Int get() = first + second val isStrike: Boolean get() = (first == 10) val isSpare: Boolean get() = (frameScore == 10) fun score(next: Frame, nextNext: Frame) = frameScore + when { isStrike -> nextNextRoll(next, nextNext) + next.first isSpare -> next.first else -> 0 } private fun nextNextRoll(next: Frame, nextNext: Frame) = if(next.isStrike) { nextNext.first } else { next.second } class Builder { private val rolls = mutableListOf() val count: Int get() = rolls.sum() val isStrike: Boolean get() = rolls.size == 1 && rolls[0] == 10 val isComplete: Boolean get() = rolls.size == 2 || isStrike fun withRoll(pins: Int): Builder { if(isComplete) { throw IllegalStateException("Frame complete") } if(pins < 0) { throw IllegalStateException("Negative roll is invalid") } if(count + pins > 10) { throw IllegalStateException("Pin count exceeds pins on the lane") } rolls.add(pins) return this } public fun build(): Frame = when (rolls.size) { 2 -> Frame(rolls[0], rolls[1]) 1 -> Frame(rolls[0], 0) else -> throw AssertionError("Frame has invalid number of rolls: " + rolls.size) } } } ================================================ FILE: exercises/practice/bowling/.meta/version ================================================ 1.0.0 ================================================ FILE: exercises/practice/bowling/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/bowling/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/bowling/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/bowling/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/bowling/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/bowling/src/main/kotlin/BowlingGame.kt ================================================ class BowlingGame { fun roll(pins: Int) { TODO("Implement the function to complete the task") } fun score() { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/bowling/src/test/kotlin/BowlingGameTest.kt ================================================ import org.junit.Ignore import org.junit.Rule import org.junit.rules.ExpectedException import kotlin.test.Test import kotlin.test.assertEquals class BowlingGameTest { @Rule @JvmField var expectedException: ExpectedException = ExpectedException.none() private fun playGame(rolls: IntArray): BowlingGame { val game = BowlingGame() rolls.forEach { game.roll(it) } return game } @Test fun `should be able to score a game with all zeros`() { val game = playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) assertEquals(0, game.score()) } @Test @Ignore fun `should be able to score a game with no strike or spares`() { val game = playGame(intArrayOf(3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6)) assertEquals(90, game.score()) } @Test @Ignore fun `a spare followed by zeros is worth ten points`() { val game = playGame(intArrayOf(6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) assertEquals(10, game.score()) } @Test @Ignore fun `points scored in the roll after a spare are counted twice`() { val game = playGame(intArrayOf(6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) assertEquals(16, game.score()) } @Test @Ignore fun `consecutive spares each get a one roll bonus`() { val game = playGame(intArrayOf(5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) assertEquals(31, game.score()) } @Test @Ignore fun `a spare in the last frame gets a one roll bonus that is counted once`() { val game = playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7)) assertEquals(17, game.score()) } @Test @Ignore fun `a strike earns ten points in frame with a single roll`() { val game = playGame(intArrayOf(10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) assertEquals(10, game.score()) } @Test @Ignore fun `points scored in the two rolls after a strike are counted twice as a bonus`() { val game = playGame(intArrayOf(10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) assertEquals(26, game.score()) } @Test @Ignore fun `consecutive strikes each get the two roll bonus`() { val game = playGame(intArrayOf(10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) assertEquals(81, game.score()) } @Test @Ignore fun `a strike in the last frame gets a two roll bonus that is counted once`() { val game = playGame(intArrayOf(10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) assertEquals(81, game.score()) } @Test @Ignore fun `rolling a spare with the two roll bonus does not get a bonus roll`() { val game = playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3)) assertEquals(20, game.score()) } @Test @Ignore fun `strikes with the two roll bonus do not get bonus rolls`() { val game = playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10)) assertEquals(30, game.score()) } @Test @Ignore fun `last two strikes followed by only last bonus with non strike points`() { val game = playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 0, 1)) assertEquals(31, game.score()) } @Test @Ignore fun `a strike with the one roll bonus after a spare in the last frame does not get a bonus`() { val game = playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10)) assertEquals(20, game.score()) } @Test @Ignore fun `all strikes is a perfect game`() { val game = playGame(intArrayOf(10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10)) assertEquals(300, game.score()) } @Test @Ignore fun `rolls can not score negative points`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) } @Test @Ignore fun `a roll can not score more than 10 points`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) } @Test @Ignore fun `two rolls in a frame can not score more than 10 points`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) } @Test @Ignore fun `bonus roll after a strike in the last frame can not score more than 10 points`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 0)) } @Test @Ignore fun `two bonus rolls after a strike in the last frame can not score more than 10 points`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 6)) } @Test @Ignore fun `two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike`() { val game = playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6)) assertEquals(26, game.score()) } @Test @Ignore fun `the second bonus rolls after a strike in the last frame can not be a strike if the first one is not a strike`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6, 10)) } @Test @Ignore fun `second bonus roll after a strike in the last frame can not score more than 10 points`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 11)) } @Test @Ignore fun `an unstarted game can not be scored`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf()).score() } @Test @Ignore fun `an incomplete game can not be scored`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 1)).score() } @Test @Ignore fun `can not roll if game already has ten frames`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) } @Test @Ignore fun `bonus rolls for a strike in the last frame must be rolled before score can be calculated`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10)).score() } @Test @Ignore fun `both bonus rolls for a strike in the last frame must be rolled before score can be calculated`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10)).score() } @Test @Ignore fun `bonus roll for a spare in the last frame must be rolled before score can be calculated`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3)).score() } @Test @Ignore fun `can not roll after bonus roll for spare`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 2, 2)).score() } @Test @Ignore fun `can not roll after bonus roll for strike`() { expectedException.expect(IllegalStateException::class.java) playGame(intArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 3, 2, 2)).score() } } ================================================ FILE: exercises/practice/change/.docs/instructions.md ================================================ # Instructions Determine the fewest number of coins to give a customer so that the sum of their values equals the correct amount of change. ## Examples - An amount of 15 with available coin values [1, 5, 10, 25, 100] should return one coin of value 5 and one coin of value 10, or [5, 10]. - An amount of 40 with available coin values [1, 5, 10, 25, 100] should return one coin of value 5, one coin of value 10, and one coin of value 25, or [5, 10, 25]. ================================================ FILE: exercises/practice/change/.docs/introduction.md ================================================ # Introduction In the mystical village of Coinholt, you stand behind the counter of your bakery, arranging a fresh batch of pastries. The door creaks open, and in walks Denara, a skilled merchant with a keen eye for quality goods. After a quick meal, she slides a shimmering coin across the counter, representing a value of 100 units. You smile, taking the coin, and glance at the total cost of the meal: 88 units. That means you need to return 12 units in change. Denara holds out her hand expectantly. "Just give me the fewest coins," she says with a smile. "My pouch is already full, and I don't want to risk losing them on the road." You know you have a few options. "We have Lumis (worth 10 units), Viras (worth 5 units), and Zenth (worth 2 units) available for change." You quickly calculate the possibilities in your head: - one Lumis (1 × 10 units) + one Zenth (1 × 2 units) = 2 coins total - two Viras (2 × 5 units) + one Zenth (1 × 2 units) = 3 coins total - six Zenth (6 × 2 units) = 6 coins total "The best choice is two coins: one Lumis and one Zenth," you say, handing her the change. Denara smiles, clearly impressed. "As always, you've got it right." ================================================ FILE: exercises/practice/change/.meta/config.json ================================================ { "authors": [ "geoand" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ChangeCalculator.kt" ], "test": [ "src/test/kotlin/ChangeCalculatorTest.kt" ], "example": [ ".meta/src/reference/kotlin/ChangeCalculator.kt" ] }, "blurb": "Correctly determine change to be given using the least number of coins.", "source": "Software Craftsmanship - Coin Change Kata", "source_url": "https://web.archive.org/web/20130115115225/http://craftsmanship.sv.cmu.edu:80/exercises/coin-change-kata" } ================================================ FILE: exercises/practice/change/.meta/src/reference/kotlin/ChangeCalculator.kt ================================================ class ChangeCalculator(coins: List) { private val sortedCoins = coins.sorted() fun computeMostEfficientChange(grandTotal: Int): List { require(grandTotal >= 0) { "Negative totals are not allowed." } val minimalCoinsMap = mutableMapOf?>() minimalCoinsMap[0] = ArrayList() for (total in 1..grandTotal) { val minimalCoins = sortedCoins .filter { it <= total } .mapNotNull { coin -> val minimalRemainderCoins = minimalCoinsMap[total - coin] if (minimalRemainderCoins != null) prepend(coin, minimalRemainderCoins) else null }.minByOrNull { it.size } minimalCoinsMap[total] = minimalCoins } return minimalCoinsMap[grandTotal] ?: throw IllegalArgumentException( "The total $grandTotal cannot be represented in the given currency.") } private fun prepend(integer: Int, integers: List): List { val result = mutableListOf() result.add(integer) result.addAll(integers) return result } } ================================================ FILE: exercises/practice/change/.meta/tests.toml ================================================ [canonical-tests] # single coin change "36887bea-7f92-4a9c-b0cc-c0e886b3ecc8" = true # multiple coin change "cef21ccc-0811-4e6e-af44-f011e7eab6c6" = true # change with Lilliputian Coins "d60952bc-0c1a-4571-bf0c-41be72690cb3" = true # change with Lower Elbonia Coins "408390b9-fafa-4bb9-b608-ffe6036edb6c" = true # large target values "7421a4cb-1c48-4bf9-99c7-7f049689132f" = true # possible change without unit coins available "f79d2e9b-0ae3-4d6a-bb58-dc978b0dba28" = true # another possible change without unit coins available "9a166411-d35d-4f7f-a007-6724ac266178" = true # no coins make 0 change "bbbcc154-e9e9-4209-a4db-dd6d81ec26bb" = true # error testing for change smaller than the smallest of coins "c8b81d5a-49bd-4b61-af73-8ee5383a2ce1" = true # error if no combination can add up to target "3c43e3e4-63f9-46ac-9476-a67516e98f68" = true # cannot find negative change values "8fe1f076-9b2d-4f44-89fe-8a6ccd63c8f3" = true ================================================ FILE: exercises/practice/change/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/change/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/change/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/change/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/change/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/change/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/change/src/main/kotlin/ChangeCalculator.kt ================================================ class ChangeCalculator { // TODO: implement proper constructor fun computeMostEfficientChange(grandTotal: Int): List { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/change/src/test/kotlin/ChangeCalculatorTest.kt ================================================ import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException import kotlin.test.assertEquals class ChangeCalculatorTest { @Rule @JvmField var expectedException: ExpectedException = ExpectedException.none() @Test fun singleCoinChange() { val computedChange = ChangeCalculator(listOf(1, 5, 10, 25, 100)).computeMostEfficientChange(25) assertContainsExactly(computedChange, listOf(25)) } @Ignore @Test fun multipleCoinChange() { val computedChange = ChangeCalculator(listOf(1, 5, 10, 25, 100)).computeMostEfficientChange(15) assertContainsExactly(computedChange, listOf(5, 10)) } @Ignore @Test fun changeWithLilliputianCoins() { val computedChange = ChangeCalculator(listOf(1, 4, 15, 20, 50)).computeMostEfficientChange(23) assertContainsExactly(computedChange, listOf(4, 4, 15)) } @Ignore @Test fun changeWithLowerElboniaCoins() { val computedChange = ChangeCalculator(listOf(1, 5, 10, 21, 25)).computeMostEfficientChange(63) assertContainsExactly(computedChange, listOf(21, 21, 21)) } @Ignore @Test fun largeTargetValues() { val computedChange = ChangeCalculator(listOf(1, 2, 5, 10, 20, 50, 100)).computeMostEfficientChange(999) assertContainsExactly(computedChange, listOf(2, 2, 5, 20, 20, 50, 100, 100, 100, 100, 100, 100, 100, 100, 100)) } @Ignore @Test fun possibleChangeWithoutUnitCoinsAvailable() { val computedChange = ChangeCalculator(listOf(2, 5, 10, 20, 50)).computeMostEfficientChange(21) assertContainsExactly(computedChange, listOf(2, 2, 2, 5, 10)) } @Ignore @Test fun anotherPossibleChangeWithoutUnitCoinsAvailable() { val computedChange = ChangeCalculator(listOf(4, 5)).computeMostEfficientChange(27) assertContainsExactly(computedChange, listOf(4, 4, 4, 5, 5, 5)) } @Ignore @Test fun noCoinsMake0Change() { val computedChange = ChangeCalculator(listOf(1, 5, 10, 21, 25)).computeMostEfficientChange(0) assertEquals(0, computedChange.size) } @Ignore @Test fun errorTestingForChangeSmallerThanTheSmallestCoin() { val changeCalculator = ChangeCalculator(listOf(5, 10)) expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("The total 3 cannot be represented in the given currency.") changeCalculator.computeMostEfficientChange(3) } @Ignore @Test fun errorIfNoCombinationCanAddUpToTarget() { val changeCalculator = ChangeCalculator(listOf(5, 10)) expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("The total 94 cannot be represented in the given currency.") changeCalculator.computeMostEfficientChange(94) } @Ignore @Test fun cannotFindNegativeChangeValues() { val changeCalculator = ChangeCalculator(listOf(1, 2, 5)) expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("Negative totals are not allowed.") changeCalculator.computeMostEfficientChange(-5) } } private inline fun assertContainsExactly(actualList: List, expectedValues: List) { assertEquals(expectedValues.size, actualList.size) expectedValues.forEach { actualList.contains(it) } } ================================================ FILE: exercises/practice/circular-buffer/.docs/instructions.md ================================================ # Instructions A circular buffer, cyclic buffer or ring buffer is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. A circular buffer first starts empty and of some predefined length. For example, this is a 7-element buffer: ```text [ ][ ][ ][ ][ ][ ][ ] ``` Assume that a 1 is written into the middle of the buffer (exact starting location does not matter in a circular buffer): ```text [ ][ ][ ][1][ ][ ][ ] ``` Then assume that two more elements are added — 2 & 3 — which get appended after the 1: ```text [ ][ ][ ][1][2][3][ ] ``` If two elements are then removed from the buffer, the oldest values inside the buffer are removed. The two elements removed, in this case, are 1 & 2, leaving the buffer with just a 3: ```text [ ][ ][ ][ ][ ][3][ ] ``` If the buffer has 7 elements then it is completely full: ```text [5][6][7][8][9][3][4] ``` When the buffer is full an error will be raised, alerting the client that further writes are blocked until a slot becomes free. When the buffer is full, the client can opt to overwrite the oldest data with a forced write. In this case, two more elements — A & B — are added and they overwrite the 3 & 4: ```text [5][6][7][8][9][A][B] ``` 3 & 4 have been replaced by A & B making 5 now the oldest data in the buffer. Finally, if two elements are removed then what would be returned is 5 & 6 yielding the buffer: ```text [ ][ ][7][8][9][A][B] ``` Because there is space available, if the client again uses overwrite to store C & D then the space where 5 & 6 were stored previously will be used not the location of 7 & 8. 7 is still the oldest element and the buffer is once again full. ```text [C][D][7][8][9][A][B] ``` ================================================ FILE: exercises/practice/circular-buffer/.meta/config.json ================================================ { "authors": [ "kahgoh" ], "files": { "solution": [ "src/main/kotlin/CircularBuffer.kt" ], "test": [ "src/test/kotlin/CircularBufferTest.kt" ], "example": [ ".meta/src/reference/kotlin/CircularBuffer.kt" ] }, "blurb": "A data structure that uses a single, fixed-size buffer as if it were connected end-to-end.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Circular_buffer" } ================================================ FILE: exercises/practice/circular-buffer/.meta/src/reference/kotlin/CircularBuffer.kt ================================================ import kotlin.collections.ArrayDeque class EmptyBufferException : Exception("Buffer is empty") {} class BufferFullException : Exception("Buffer is full") {} class CircularBuffer(private val capacity: Int) { private val contents = ArrayDeque(capacity) fun read() : T { if (contents.isNotEmpty()) { return contents.removeFirst() } throw EmptyBufferException() } fun write(value: T) { if (contents.size < capacity) { contents.add(value) } else { throw BufferFullException() } } fun overwrite(value: T) { if (contents.size >= capacity) { contents.removeFirst() } contents.add(value) } fun clear() { contents.clear() } } ================================================ FILE: exercises/practice/circular-buffer/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [28268ed4-4ff3-45f3-820e-895b44d53dfa] description = "reading empty buffer should fail" [2e6db04a-58a1-425d-ade8-ac30b5f318f3] description = "can read an item just written" [90741fe8-a448-45ce-be2b-de009a24c144] description = "each item may only be read once" [be0e62d5-da9c-47a8-b037-5db21827baa7] description = "items are read in the order they are written" [2af22046-3e44-4235-bfe6-05ba60439d38] description = "full buffer can't be written to" [547d192c-bbf0-4369-b8fa-fc37e71f2393] description = "a read frees up capacity for another write" [04a56659-3a81-4113-816b-6ecb659b4471] description = "read position is maintained even across multiple writes" [60c3a19a-81a7-43d7-bb0a-f07242b1111f] description = "items cleared out of buffer can't be read" [45f3ae89-3470-49f3-b50e-362e4b330a59] description = "clear frees up capacity for another write" [e1ac5170-a026-4725-bfbe-0cf332eddecd] description = "clear does nothing on empty buffer" [9c2d4f26-3ec7-453f-a895-7e7ff8ae7b5b] description = "overwrite acts like write on non-full buffer" [880f916b-5039-475c-bd5c-83463c36a147] description = "overwrite replaces the oldest item on full buffer" [bfecab5b-aca1-4fab-a2b0-cd4af2b053c3] description = "overwrite replaces the oldest item remaining in buffer following a read" [9cebe63a-c405-437b-8b62-e3fdc1ecec5a] description = "initial clear does not affect wrapping around" ================================================ FILE: exercises/practice/circular-buffer/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/circular-buffer/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/circular-buffer/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/circular-buffer/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/circular-buffer/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/circular-buffer/src/main/kotlin/CircularBuffer.kt ================================================ import kotlin.collections.ArrayDeque // TODO: implement proper exceptions to complete the task class EmptyBufferException class BufferFullException class CircularBuffer { // TODO: implement proper constructor to complete the task fun read() : T { TODO("Implement this function to complete the task") } fun write(value: T) { TODO("Implement this function to complete the task") } fun overwrite(value: T) { TODO("Implement this function to complete the task") } fun clear() { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/circular-buffer/src/test/kotlin/CircularBufferTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals import kotlin.test.assertFailsWith class CircularBufferTest { @Test fun `reading empty buffer should fail`() { val buffer = CircularBuffer(1) assertFailsWith() { buffer.read() } } @Ignore @Test fun `can read an item just written`() { val buffer = CircularBuffer(1) buffer.write(1) assertEquals(1, buffer.read()) } @Ignore @Test fun `each item may only be read once`() { val buffer = CircularBuffer(1) buffer.write(1) assertEquals(1, buffer.read()) assertFailsWith { buffer.read() } } @Ignore @Test fun `items are read in the order they are written`() { val buffer = CircularBuffer(2) buffer.write(1) buffer.write(2) assertEquals(1, buffer.read()) assertEquals(2, buffer.read()) } @Ignore @Test fun `full buffer can't be written to`() { val buffer = CircularBuffer(1) buffer.write(1) assertFailsWith { buffer.write(2) } } @Ignore @Test fun `a read frees up capacity for another write`() { val buffer = CircularBuffer(1) buffer.write(1) assertEquals(1, buffer.read()) buffer.write(2) assertEquals(2, buffer.read()) } @Ignore @Test fun `read position is maintained even across multiple writes`() { val buffer = CircularBuffer(3) buffer.write(1) buffer.write(2) assertEquals(1, buffer.read()) buffer.write(3) assertEquals(2, buffer.read()) assertEquals(3, buffer.read()) } @Ignore @Test fun `items cleared out of buffer can't be read`() { val buffer = CircularBuffer(1) buffer.write(1) buffer.clear() assertFailsWith { buffer.read() } } @Ignore @Test fun `clear frees up capacity for another write`() { val buffer = CircularBuffer(1) buffer.write(1) buffer.clear() buffer.write(2) assertEquals(2, buffer.read()) } @Ignore @Test fun `clear does nothing on empty buffer`() { val buffer = CircularBuffer(1) buffer.clear() buffer.write(1) assertEquals(1, buffer.read()) } @Ignore @Test fun `overwrite acts like write on non-full buffer`() { val buffer = CircularBuffer(2) buffer.write(1) buffer.overwrite(2) assertEquals(1, buffer.read()) assertEquals(2, buffer.read()) } @Ignore @Test fun `overwrite replaces the oldest item on full buffer`() { val buffer = CircularBuffer(2) buffer.write(1) buffer.write(2) buffer.overwrite(3) assertEquals(2, buffer.read()) assertEquals(3, buffer.read()) } @Ignore @Test fun `overwrite replaces the oldest item remaining in buffer following a read`() { val buffer = CircularBuffer(3) buffer.write(1) buffer.write(2) buffer.write(3) assertEquals(1, buffer.read()) buffer.write(4) buffer.overwrite(5) assertEquals(3, buffer.read()) assertEquals(4, buffer.read()) assertEquals(5, buffer.read()) } @Ignore @Test fun `initial clear does not affect wrapping around`() { val buffer = CircularBuffer(2) buffer.clear() buffer.write(1) buffer.write(2) buffer.overwrite(3) buffer.overwrite(4) assertEquals(3, buffer.read()) assertEquals(4, buffer.read()) assertFailsWith { buffer.read() } } } ================================================ FILE: exercises/practice/clock/.docs/instructions.md ================================================ # Instructions Implement a clock that handles times without dates. You should be able to add and subtract minutes to it. Two clocks that represent the same time should be equal to each other. ================================================ FILE: exercises/practice/clock/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Clock.kt" ], "test": [ "src/test/kotlin/ClockCreationTest.kt", "src/test/kotlin/ClockAddTest.kt", "src/test/kotlin/ClockSubtractTest.kt", "src/test/kotlin/ClockEqualTest.kt" ], "example": [ ".meta/src/reference/kotlin/Clock.kt" ] }, "blurb": "Implement a clock that handles times without dates.", "source": "Pairing session with Erin Drummond" } ================================================ FILE: exercises/practice/clock/.meta/src/reference/kotlin/Clock.kt ================================================ data class Clock(private var hours: Int, private var minutes: Int) { companion object { private const val MINUTES_IN_AN_HOUR = 60 private const val HOURS_IN_A_DAY = 24 } init { sanitiseTime() } override fun toString(): String { return "${hours.toTimeString()}:${minutes.toTimeString()}" } fun add(minutes: Int) { this.minutes += minutes sanitiseTime() } fun subtract(minutes: Int) = add(minutes * -1) private fun sanitiseTime() { while (minutes < 0) { minutes += MINUTES_IN_AN_HOUR hours-- } while (hours < 0) { hours += HOURS_IN_A_DAY } val minutesOverflow = minutes / MINUTES_IN_AN_HOUR minutes %= MINUTES_IN_AN_HOUR hours = (hours + minutesOverflow) % HOURS_IN_A_DAY } } private fun Int.toTimeString(): String { return toString().padStart(length = 2, padChar = '0') } ================================================ FILE: exercises/practice/clock/.meta/tests.toml ================================================ [canonical-tests] # on the hour "a577bacc-106b-496e-9792-b3083ea8705e" = true # past the hour "b5d0c360-3b88-489b-8e84-68a1c7a4fa23" = true # midnight is zero hours "473223f4-65f3-46ff-a9f7-7663c7e59440" = true # hour rolls over "ca95d24a-5924-447d-9a96-b91c8334725c" = true # hour rolls over continuously "f3826de0-0925-4d69-8ac8-89aea7e52b78" = true # sixty minutes is next hour "a02f7edf-dfd4-4b11-b21a-86de3cc6a95c" = true # minutes roll over "8f520df6-b816-444d-b90f-8a477789beb5" = true # minutes roll over continuously "c75c091b-47ac-4655-8d40-643767fc4eed" = true # hour and minutes roll over "06343ecb-cf39-419d-a3f5-dcbae0cc4c57" = true # hour and minutes roll over continuously "be60810e-f5d9-4b58-9351-a9d1e90e660c" = true # hour and minutes roll over to exactly midnight "1689107b-0b5c-4bea-aad3-65ec9859368a" = true # negative hour "d3088ee8-91b7-4446-9e9d-5e2ad6219d91" = true # negative hour rolls over "77ef6921-f120-4d29-bade-80d54aa43b54" = true # negative hour rolls over continuously "359294b5-972f-4546-bb9a-a85559065234" = true # negative minutes "509db8b7-ac19-47cc-bd3a-a9d2f30b03c0" = true # negative minutes roll over "5d6bb225-130f-4084-84fd-9e0df8996f2a" = true # negative minutes roll over continuously "d483ceef-b520-4f0c-b94a-8d2d58cf0484" = true # negative sixty minutes is previous hour "1cd19447-19c6-44bf-9d04-9f8305ccb9ea" = true # negative hour and minutes both roll over "9d3053aa-4f47-4afc-bd45-d67a72cef4dc" = true # negative hour and minutes both roll over continuously "51d41fcf-491e-4ca0-9cae-2aa4f0163ad4" = true # add minutes "d098e723-ad29-4ef9-997a-2693c4c9d89a" = true # add no minutes "b6ec8f38-e53e-4b22-92a7-60dab1f485f4" = true # add to next hour "efd349dd-0785-453e-9ff8-d7452a8e7269" = true # add more than one hour "749890f7-aba9-4702-acce-87becf4ef9fe" = true # add more than two hours with carry "da63e4c1-1584-46e3-8d18-c9dc802c1713" = true # add across midnight "be167a32-3d33-4cec-a8bc-accd47ddbb71" = true # add more than one day (1500 min = 25 hrs) "6672541e-cdae-46e4-8be7-a820cc3be2a8" = true # add more than two days "1918050d-c79b-4cb7-b707-b607e2745c7e" = true # subtract minutes "37336cac-5ede-43a5-9026-d426cbe40354" = true # subtract to previous hour "0aafa4d0-3b5f-4b12-b3af-e3a9e09c047b" = true # subtract more than an hour "9b4e809c-612f-4b15-aae0-1df0acb801b9" = true # subtract across midnight "8b04bb6a-3d33-4e6c-8de9-f5de6d2c70d6" = true # subtract more than two hours "07c3bbf7-ce4d-4658-86e8-4a77b7a5ccd9" = true # subtract more than two hours with borrow "90ac8a1b-761c-4342-9c9c-cdc3ed5db097" = true # subtract more than one day (1500 min = 25 hrs) "2149f985-7136-44ad-9b29-ec023a97a2b7" = true # subtract more than two days "ba11dbf0-ac27-4acb-ada9-3b853ec08c97" = true # clocks with same time "f2fdad51-499f-4c9b-a791-b28c9282e311" = true # clocks a minute apart "5d409d4b-f862-4960-901e-ec430160b768" = true # clocks an hour apart "a6045fcf-2b52-4a47-8bb2-ef10a064cba5" = true # clocks with hour overflow "66b12758-0be5-448b-a13c-6a44bce83527" = true # clocks with hour overflow by several days "2b19960c-212e-4a71-9aac-c581592f8111" = true # clocks with negative hour "6f8c6541-afac-4a92-b0c2-b10d4e50269f" = true # clocks with negative hour that wraps "bb9d5a68-e324-4bf5-a75e-0e9b1f97a90d" = true # clocks with negative hour that wraps multiple times "56c0326d-565b-4d19-a26f-63b3205778b7" = true # clocks with minute overflow "c90b9de8-ddff-4ffe-9858-da44a40fdbc2" = true # clocks with minute overflow by several days "533a3dc5-59a7-491b-b728-a7a34fe325de" = true # clocks with negative minute "fff49e15-f7b7-4692-a204-0f6052d62636" = true # clocks with negative minute that wraps "605c65bb-21bd-43eb-8f04-878edf508366" = true # clocks with negative minute that wraps multiple times "b87e64ed-212a-4335-91fd-56da8421d077" = true # clocks with negative hours and minutes "822fbf26-1f3b-4b13-b9bf-c914816b53dd" = true # clocks with negative hours and minutes that wrap "e787bccd-cf58-4a1d-841c-ff80eaaccfaa" = true # full clock and zeroed clock "96969ca8-875a-48a1-86ae-257a528c44f5" = true ================================================ FILE: exercises/practice/clock/.meta/version ================================================ 2.4.0 ================================================ FILE: exercises/practice/clock/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/clock/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/clock/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/clock/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/clock/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/clock/src/main/kotlin/Clock.kt ================================================ class Clock { //TODO: implement proper constructor //TODO: find a convenient way to take over `toString()` and `equals()` fun subtract(minutes: Int) { TODO("Implement the function to complete the task") } fun add(minutes: Int) { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/clock/src/test/kotlin/ClockAddTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class ClockAddTest { @Ignore @Test fun `add minutes`() = Clock(10, 0) .plusMinutes(3) .shouldBe("10:03") @Ignore @Test fun `add no minutes`() = Clock(6, 41) .plusMinutes(0) .shouldBe("06:41") @Ignore @Test fun `add to next hour`() = Clock(0, 45) .plusMinutes(40) .shouldBe("01:25") @Ignore @Test fun `add more than one hour`() = Clock(10, 0) .plusMinutes(61) .shouldBe("11:01") @Ignore @Test fun `add more than two hours with carry`() = Clock(0, 45) .plusMinutes(160) .shouldBe("03:25") @Ignore @Test fun `add across midnight`() = Clock(23, 59) .plusMinutes(2) .shouldBe("00:01") @Ignore @Test fun `add more than one day`() = Clock(5, 32) .plusMinutes(1500) .shouldBe("06:32") @Ignore @Test fun `add more than two days`() = Clock(1, 1) .plusMinutes(3500) .shouldBe("11:21") } private fun Clock.plusMinutes(minutes: Int): Clock { add(minutes) return this } private fun Clock.shouldBe(expectation: String) = assertEquals(expectation, toString()) ================================================ FILE: exercises/practice/clock/src/test/kotlin/ClockCreationTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class ClockCreationTest { @Test fun `on the hour`() = assertEquals("08:00", Clock(8, 0).toString()) @Ignore @Test fun `past the hour`() = assertEquals("11:09", Clock(11, 9).toString()) @Ignore @Test fun `midnight is zero hours`() = assertEquals("00:00", Clock(24, 0).toString()) @Ignore @Test fun `hour rolls over`() = assertEquals("01:00", Clock(25, 0).toString()) @Ignore @Test fun `hour rolls over continuously`() = assertEquals("04:00", Clock(100, 0).toString()) @Ignore @Test fun `sixty minutes is next hour`() = assertEquals("02:00", Clock(1, 60).toString()) @Ignore @Test fun `minutes roll over`() = assertEquals("02:40", Clock(0, 160).toString()) @Ignore @Test fun `minutes roll over continuously`() = assertEquals("04:43", Clock(0, 1723).toString()) @Ignore @Test fun `hour and minutes roll over`() = assertEquals("03:40", Clock(25, 160).toString()) @Ignore @Test fun `hour and minutes roll over continuously`() = assertEquals("11:01", Clock(201, 3001).toString()) @Ignore @Test fun `hour and minutes roll over to exactly midnight`() = assertEquals("00:00", Clock(72, 8640).toString()) @Ignore @Test fun `negative hour`() = assertEquals("23:15", Clock(-1, 15).toString()) @Ignore @Test fun `negative hour rolls over`() = assertEquals("23:00", Clock(-25, 0).toString()) @Ignore @Test fun `negative hour rolls over continuously`() = assertEquals("05:00", Clock(-91, 0).toString()) @Ignore @Test fun `negative minutes`() = assertEquals("00:20", Clock(1, -40).toString()) @Ignore @Test fun `negative minutes roll over`() = assertEquals("22:20", Clock(1, -160).toString()) @Ignore @Test fun `negative minutes roll over continuously`() = assertEquals("16:40", Clock(1, -4820).toString()) @Ignore @Test fun `negative sixty minutes is previous hour`() = assertEquals("01:00", Clock(2, -60).toString()) @Ignore @Test fun `negative hour and minutes both roll over`() = assertEquals("20:20", Clock(-25, -160).toString()) @Ignore @Test fun `negative hour and minutes both roll over continuously`() = assertEquals("22:10", Clock(-121, -5810).toString()) } ================================================ FILE: exercises/practice/clock/src/test/kotlin/ClockEqualTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertNotEquals import kotlin.test.assertEquals class ClockEqualTest { @Ignore @Test fun `same time`() = assertEquals(Clock(15, 37), Clock(15, 37)) @Ignore @Test fun `clocks a minute apart`() = assertNotEquals(Clock(15, 36), Clock(15, 37)) @Ignore @Test fun `clocks an hour apart`() = assertNotEquals(Clock(14, 37), Clock(15, 37)) @Ignore @Test fun `hour overflow`() = assertEquals(Clock(10, 37), Clock(34, 37)) @Ignore @Test fun `hour overflow by several days`() = assertEquals(Clock(3, 11), Clock(99, 11)) @Ignore @Test fun `negative hour`() = assertEquals(Clock(22, 40), Clock(-2, 40)) @Ignore @Test fun `negative hour that wraps`() = assertEquals(Clock(17, 3), Clock(-31, 3)) @Ignore @Test fun `negative hour that wraps multiple times`() = assertEquals(Clock(13, 49), Clock(-83, 49)) @Ignore @Test fun `minute overflow`() = assertEquals(Clock(0, 1), Clock(0, 1441)) @Ignore @Test fun `minute overflow by several days`() = assertEquals(Clock(2, 2), Clock(2, 4322)) @Ignore @Test fun `negative minute`() = assertEquals(Clock(2, 40), Clock(3, -20)) @Ignore @Test fun `negative minute that wraps`() = assertEquals(Clock(4, 10), Clock(5, -1490)) @Ignore @Test fun `negative minute that wraps multiple times`() = assertEquals(Clock(6, 15), Clock(6, -4305)) @Ignore @Test fun `negative hours and minutes`() = assertEquals(Clock(7, 32), Clock(-12, -268)) @Ignore @Test fun `negative hours and minutes that wrap`() = assertEquals(Clock(18, 7), Clock(-54, -11513)) @Ignore @Test fun `full clock and zeroed clock`() = assertEquals(Clock(24, 0), Clock(0, 0)) } ================================================ FILE: exercises/practice/clock/src/test/kotlin/ClockSubtractTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class ClockSubtractTest { @Ignore @Test fun `subtract minutes`() = Clock(10, 3) .minusMinutes(3) .shouldBe("10:00") @Ignore @Test fun `subtract to previous hour`() = Clock(10, 3) .minusMinutes(30) .shouldBe("09:33") @Ignore @Test fun `subtract more than an hour`() = Clock(10, 3) .minusMinutes(70) .shouldBe("08:53") @Ignore @Test fun `subtract across midnight`() = Clock(0, 3) .minusMinutes(4) .shouldBe("23:59") @Ignore @Test fun `subtract more than two hours`() = Clock(0, 0) .minusMinutes(160) .shouldBe("21:20") @Ignore @Test fun `subtract more than two hours with borrow`() = Clock(6, 15) .minusMinutes(160) .shouldBe("03:35") @Ignore @Test fun `subtract more than one day`() = Clock(5, 32) .minusMinutes(1500) .shouldBe("04:32") @Ignore @Test fun `subtract more than two days`() = Clock(2, 20) .minusMinutes(3000) .shouldBe("00:20") } private fun Clock.minusMinutes(minutes: Int): Clock { subtract(minutes) return this } private fun Clock.shouldBe(expectation: String) = assertEquals(expectation, toString()) ================================================ FILE: exercises/practice/collatz-conjecture/.docs/instructions.md ================================================ # Instructions Given a positive integer, return the number of steps it takes to reach 1 according to the rules of the Collatz Conjecture. ================================================ FILE: exercises/practice/collatz-conjecture/.docs/introduction.md ================================================ # Introduction One evening, you stumbled upon an old notebook filled with cryptic scribbles, as though someone had been obsessively chasing an idea. On one page, a single question stood out: **Can every number find its way to 1?** It was tied to something called the **Collatz Conjecture**, a puzzle that has baffled thinkers for decades. The rules were deceptively simple. Pick any positive integer. - If it's even, divide it by 2. - If it's odd, multiply it by 3 and add 1. Then, repeat these steps with the result, continuing indefinitely. Curious, you picked number 12 to test and began the journey: 12 ➜ 6 ➜ 3 ➜ 10 ➜ 5 ➜ 16 ➜ 8 ➜ 4 ➜ 2 ➜ 1 Counting from the second number (6), it took 9 steps to reach 1, and each time the rules repeated, the number kept changing. At first, the sequence seemed unpredictable — jumping up, down, and all over. Yet, the conjecture claims that no matter the starting number, we'll always end at 1. It was fascinating, but also puzzling. Why does this always seem to work? Could there be a number where the process breaks down, looping forever or escaping into infinity? The notebook suggested solving this could reveal something profound — and with it, fame, [fortune][collatz-prize], and a place in history awaits whoever could unlock its secrets. [collatz-prize]: https://mathprize.net/posts/collatz-conjecture/ ================================================ FILE: exercises/practice/collatz-conjecture/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/CollatzCalculator.kt" ], "test": [ "src/test/kotlin/CollatzCalculatorTest.kt" ], "example": [ ".meta/src/reference/kotlin/CollatzCalculator.kt" ] }, "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Collatz_conjecture" } ================================================ FILE: exercises/practice/collatz-conjecture/.meta/src/reference/kotlin/CollatzCalculator.kt ================================================ object CollatzCalculator { fun computeStepCount(start: Int): Int { require(start > 0) { "Only natural numbers are allowed" } if (start == 1) return 0 val next = if (start % 2 == 0) start / 2 else 3 * start + 1 return 1 + computeStepCount(next) } } ================================================ FILE: exercises/practice/collatz-conjecture/.meta/tests.toml ================================================ [canonical-tests] # zero steps for one "540a3d51-e7a6-47a5-92a3-4ad1838f0bfd" = true # divide if even "3d76a0a6-ea84-444a-821a-f7857c2c1859" = true # even and odd steps "754dea81-123c-429e-b8bc-db20b05a87b9" = true # large number of even and odd steps "ecfd0210-6f85-44f6-8280-f65534892ff6" = true # zero is an error "7d4750e6-def9-4b86-aec7-9f7eb44f95a3" = true # negative value is an error "c6c795bf-a288-45e9-86a1-841359ad426d" = true ================================================ FILE: exercises/practice/collatz-conjecture/.meta/version ================================================ 1.2.1 ================================================ FILE: exercises/practice/collatz-conjecture/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/collatz-conjecture/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/collatz-conjecture/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/collatz-conjecture/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/collatz-conjecture/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/collatz-conjecture/src/main/kotlin/CollatzCalculator.kt ================================================ object CollatzCalculator { fun computeStepCount(start: Int): Int { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/collatz-conjecture/src/test/kotlin/CollatzCalculatorTest.kt ================================================ import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException import kotlin.test.assertEquals class CollatzCalculatorTest { @Rule @JvmField var expectedException: ExpectedException = ExpectedException.none() @Test fun `zero steps for 1`() = assertStepsEqual(1, 0) @Ignore @Test fun `divide if even`() = assertStepsEqual(16, 4) @Ignore @Test fun `even and odd steps`() = assertStepsEqual(12, 9) @Ignore @Test fun `large number of even and odd steps`() = assertStepsEqual(1000000, 152) @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid input - zero`() { steps(0) } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid input - negative`() { steps(-15) } } private fun assertStepsEqual(input: Int, steps: Int) = assertEquals(steps, steps(input)) private fun steps(input: Int) = CollatzCalculator.computeStepCount(input) ================================================ FILE: exercises/practice/complex-numbers/.docs/instructions.md ================================================ # Instructions A **complex number** is expressed in the form `z = a + b * i`, where: - `a` is the **real part** (a real number), - `b` is the **imaginary part** (also a real number), and - `i` is the **imaginary unit** satisfying `i^2 = -1`. ## Operations on Complex Numbers ### Conjugate The conjugate of the complex number `z = a + b * i` is given by: ```text zc = a - b * i ``` ### Absolute Value The absolute value (or modulus) of `z` is defined as: ```text |z| = sqrt(a^2 + b^2) ``` The square of the absolute value is computed as the product of `z` and its conjugate `zc`: ```text |z|^2 = z * zc = a^2 + b^2 ``` ### Addition The sum of two complex numbers `z1 = a + b * i` and `z2 = c + d * i` is computed by adding their real and imaginary parts separately: ```text z1 + z2 = (a + b * i) + (c + d * i) = (a + c) + (b + d) * i ``` ### Subtraction The difference of two complex numbers is obtained by subtracting their respective parts: ```text z1 - z2 = (a + b * i) - (c + d * i) = (a - c) + (b - d) * i ``` ### Multiplication The product of two complex numbers is defined as: ```text z1 * z2 = (a + b * i) * (c + d * i) = (a * c - b * d) + (b * c + a * d) * i ``` ### Reciprocal The reciprocal of a non-zero complex number is given by: ```text 1 / z = 1 / (a + b * i) = a / (a^2 + b^2) - b / (a^2 + b^2) * i ``` ### Division The division of one complex number by another is given by: ```text z1 / z2 = z1 * (1 / z2) = (a + b * i) / (c + d * i) = (a * c + b * d) / (c^2 + d^2) + (b * c - a * d) / (c^2 + d^2) * i ``` ### Exponentiation Raising _e_ (the base of the natural logarithm) to a complex exponent can be expressed using Euler's formula: ```text e^(a + b * i) = e^a * e^(b * i) = e^a * (cos(b) + i * sin(b)) ``` ## Implementation Requirements Given that you should not use built-in support for complex numbers, implement the following operations: - **addition** of two complex numbers - **subtraction** of two complex numbers - **multiplication** of two complex numbers - **division** of two complex numbers - **conjugate** of a complex number - **absolute value** of a complex number - **exponentiation** of _e_ (the base of the natural logarithm) to a complex number ================================================ FILE: exercises/practice/complex-numbers/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "DanCorder", "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ComplexNumber.kt" ], "test": [ "src/test/kotlin/ComplexNumberTest.kt" ], "example": [ ".meta/src/reference/kotlin/ComplexNumber.kt" ] }, "blurb": "Implement complex numbers.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Complex_number" } ================================================ FILE: exercises/practice/complex-numbers/.meta/src/reference/kotlin/ComplexNumber.kt ================================================ import kotlin.math.* data class ComplexNumber(val real: Double = 0.0, val imag: Double = 0.0) { val abs = hypot(real, imag) operator fun plus(other: ComplexNumber) = copy(real = real + other.real, imag = imag + other.imag) operator fun minus(other: ComplexNumber) = copy(real = real - other.real, imag = imag - other.imag) operator fun times(other: ComplexNumber) = copy(real = real*other.real - imag*other.imag, imag = real*other.imag + imag*other.real) operator fun div(other: ComplexNumber) = this * other.conjugate() / other.abs.pow(2.0) operator fun times(factor: Double) = copy(real = factor * real, imag = factor * imag) operator fun div(factor: Double) = copy(real = real / factor, imag = imag / factor) fun conjugate() = copy(imag = -1 * imag) } fun exponential(exponent: ComplexNumber) = ComplexNumber(real = cos(exponent.imag), imag = sin(exponent.imag)) * exp(exponent.real) ================================================ FILE: exercises/practice/complex-numbers/.meta/tests.toml ================================================ [canonical-tests] # Real part of a purely real number "9f98e133-eb7f-45b0-9676-cce001cd6f7a" = true # Real part of a purely imaginary number "07988e20-f287-4bb7-90cf-b32c4bffe0f3" = true # Real part of a number with real and imaginary part "4a370e86-939e-43de-a895-a00ca32da60a" = true # Imaginary part of a purely real number "9b3fddef-4c12-4a99-b8f8-e3a42c7ccef6" = true # Imaginary part of a purely imaginary number "a8dafedd-535a-4ed3-8a39-fda103a2b01e" = true # Imaginary part of a number with real and imaginary part "0f998f19-69ee-4c64-80ef-01b086feab80" = true # Imaginary unit "a39b7fd6-6527-492f-8c34-609d2c913879" = true # Add purely real numbers "9a2c8de9-f068-4f6f-b41c-82232cc6c33e" = true # Add purely imaginary numbers "657c55e1-b14b-4ba7-bd5c-19db22b7d659" = true # Add numbers with real and imaginary part "4e1395f5-572b-4ce8-bfa9-9a63056888da" = true # Subtract purely real numbers "1155dc45-e4f7-44b8-af34-a91aa431475d" = true # Subtract purely imaginary numbers "f95e9da8-acd5-4da4-ac7c-c861b02f774b" = true # Subtract numbers with real and imaginary part "f876feb1-f9d1-4d34-b067-b599a8746400" = true # Multiply purely real numbers "8a0366c0-9e16-431f-9fd7-40ac46ff4ec4" = true # Multiply purely imaginary numbers "e560ed2b-0b80-4b4f-90f2-63cefc911aaf" = true # Multiply numbers with real and imaginary part "4d1d10f0-f8d4-48a0-b1d0-f284ada567e6" = true # Divide purely real numbers "b0571ddb-9045-412b-9c15-cd1d816d36c1" = true # Divide purely imaginary numbers "5bb4c7e4-9934-4237-93cc-5780764fdbdd" = true # Divide numbers with real and imaginary part "c4e7fef5-64ac-4537-91c2-c6529707701f" = true # Absolute value of a positive purely real number "c56a7332-aad2-4437-83a0-b3580ecee843" = true # Absolute value of a negative purely real number "cf88d7d3-ee74-4f4e-8a88-a1b0090ecb0c" = true # Absolute value of a purely imaginary number with positive imaginary part "bbe26568-86c1-4bb4-ba7a-da5697e2b994" = true # Absolute value of a purely imaginary number with negative imaginary part "3b48233d-468e-4276-9f59-70f4ca1f26f3" = true # Absolute value of a number with real and imaginary part "fe400a9f-aa22-4b49-af92-51e0f5a2a6d3" = true # Conjugate a purely real number "fb2d0792-e55a-4484-9443-df1eddfc84a2" = true # Conjugate a purely imaginary number "e37fe7ac-a968-4694-a460-66cb605f8691" = true # Conjugate a number with real and imaginary part "f7704498-d0be-4192-aaf5-a1f3a7f43e68" = true # Euler's identity/formula "6d96d4c6-2edb-445b-94a2-7de6d4caaf60" = true # Exponential of 0 "2d2c05a0-4038-4427-a24d-72f6624aa45f" = true # Exponential of a purely real number "ed87f1bd-b187-45d6-8ece-7e331232c809" = true # Exponential of a number with real and imaginary part "08eedacc-5a95-44fc-8789-1547b27a8702" = true ================================================ FILE: exercises/practice/complex-numbers/.meta/version ================================================ 1.3.0 ================================================ FILE: exercises/practice/complex-numbers/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/complex-numbers/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/complex-numbers/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/complex-numbers/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/complex-numbers/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/complex-numbers/src/main/kotlin/ComplexNumber.kt ================================================ data class ComplexNumber(val real: Double = 0.0, val imag: Double = 0.0) ================================================ FILE: exercises/practice/complex-numbers/src/test/kotlin/ComplexNumberTest.kt ================================================ import org.junit.Assert.assertEquals import org.junit.Ignore import org.junit.Test import kotlin.math.* class ComplexNumberTest { // Test helpers companion object { private const val DOUBLE_EQUALITY_TOLERANCE = 1e-15 } private fun assertDoublesEqual(d1: Double, d2: Double) { assertEquals(d1, d2, DOUBLE_EQUALITY_TOLERANCE) } private fun assertComplexNumbersEqual(c1: ComplexNumber, c2: ComplexNumber) { assertDoublesEqual(c1.real, c2.real) assertDoublesEqual(c1.imag, c2.imag) } // Tests @Test fun testImaginaryUnitExhibitsDefiningProperty() { val expected = ComplexNumber(real = -1.0) val actual = ComplexNumber(imag = 1.0) * ComplexNumber(imag = 1.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testAdditionWithPurelyRealNumbers() { val expected = ComplexNumber(real = 3.0) val actual = ComplexNumber(real = 1.0) + ComplexNumber(real = 2.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testAdditionWithPurelyImaginaryNumbers() { val expected = ComplexNumber(imag = 3.0) val actual = ComplexNumber(imag = 1.0) + ComplexNumber(imag = 2.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testAdditionWithRealAndImaginaryParts() { val expected = ComplexNumber(real = 4.0, imag = 6.0) val actual = ComplexNumber(real = 1.0, imag = 2.0) + ComplexNumber(real = 3.0, imag = 4.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testSubtractionWithPurelyRealNumbers() { val expected = ComplexNumber(real = -1.0, imag = 0.0) val actual = ComplexNumber(real = 1.0, imag = 0.0) - ComplexNumber(real = 2.0, imag = 0.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testSubtractionWithPurelyImaginaryNumbers() { val expected = ComplexNumber(imag = -1.0) val actual = ComplexNumber(imag = 1.0) - ComplexNumber(imag = 2.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testSubtractionWithRealAndImaginaryParts() { val expected = ComplexNumber(real = -2.0, imag = -2.0) val actual = ComplexNumber(real = 1.0, imag = 2.0) - ComplexNumber(real = 3.0, imag = 4.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testMultiplicationWithPurelyRealNumbers() { val expected = ComplexNumber(real = 2.0) val actual = ComplexNumber(real = 1.0) * ComplexNumber(real = 2.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testMultiplicationWithPurelyImaginaryNumbers() { val expected = ComplexNumber(real = -2.0) val actual = ComplexNumber(imag = 1.0) * ComplexNumber(imag = 2.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testMultiplicationWithRealAndImaginaryParts() { val expected = ComplexNumber(real = -5.0, imag = 10.0) val actual = ComplexNumber(real = 1.0, imag = 2.0) * ComplexNumber(real = 3.0, imag = 4.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testDivisionWithPurelyRealNumbers() { val expected = ComplexNumber(real = 0.5) val actual = ComplexNumber(real = 1.0) / ComplexNumber(real = 2.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testDivisionWithPurelyImaginaryNumbers() { val expected = ComplexNumber(real = 0.5) val actual = ComplexNumber(imag = 1.0) / ComplexNumber(imag = 2.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testDivisionWithRealAndImaginaryParts() { val expected = ComplexNumber(real = 0.44, imag = 0.08) val actual = ComplexNumber(real = 1.0, imag = 2.0) / ComplexNumber(real = 3.0, imag = 4.0) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testAbsoluteValueOfPositivePurelyRealNumber() { val expected = 5.0 val actual = ComplexNumber(real = 5.0).abs assertDoublesEqual(expected, actual) } @Ignore @Test fun testAbsoluteValueOfNegativePurelyRealNumber() { val expected = 5.0 val actual = ComplexNumber(real = -5.0).abs assertDoublesEqual(expected, actual) } @Ignore @Test fun testAbsoluteValueOfPurelyImaginaryNumberWithPositiveImaginaryPart() { val expected = 5.0 val actual = ComplexNumber(imag = 5.0).abs assertDoublesEqual(expected, actual) } @Ignore @Test fun testAbsoluteValueOfPurelyImaginaryNumberWithNegativeImaginaryPart() { val expected = 5.0 val actual = ComplexNumber(imag = -5.0).abs assertDoublesEqual(expected, actual) } @Ignore @Test fun testAbsoluteValueOfNumberWithRealAndImaginaryParts() { val expected = 5.0 val actual = ComplexNumber(real = 3.0, imag = 4.0).abs assertDoublesEqual(expected, actual) } @Ignore @Test fun testConjugationOfPurelyRealNumber() { val expected = ComplexNumber(real = 5.0) val actual = ComplexNumber(real = 5.0).conjugate() assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testConjugationOfPurelyImaginaryNumber() { val expected = ComplexNumber(imag = -5.0) val actual = ComplexNumber(imag = 5.0).conjugate() assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testConjugationOfNumberWithRealAndImaginaryParts() { val expected = ComplexNumber(real = 1.0, imag = -1.0) val actual = ComplexNumber(real = 1.0, imag = 1.0).conjugate() assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testRealPartOfPurelyRealNumber() { val expected = 1.0 val actual = ComplexNumber(real = 1.0).real assertDoublesEqual(expected, actual) } @Ignore @Test fun testRealPartOfPurelyImaginaryNumber() { val expected = 0.0 val actual = ComplexNumber(imag = 1.0).real assertDoublesEqual(expected, actual) } @Ignore @Test fun testRealPartOfNumberWithRealAndImaginaryParts() { val expected = 1.0 val actual = ComplexNumber(real = 1.0, imag = 2.0).real assertDoublesEqual(expected, actual) } @Ignore @Test fun testImaginaryPartOfPurelyRealNumber() { val expected = 0.0 val actual = ComplexNumber(real = 1.0).imag assertDoublesEqual(expected, actual) } @Ignore @Test fun testImaginaryPartOfPurelyImaginaryNumber() { val expected = 1.0 val actual = ComplexNumber(imag = 1.0).imag assertDoublesEqual(expected, actual) } @Ignore @Test fun testImaginaryPartOfNumberWithRealAndImaginaryParts() { val expected = 2.0 val actual = ComplexNumber(real = 1.0, imag = 2.0).imag assertDoublesEqual(expected, actual) } @Ignore @Test fun testExponentialOfPurelyImaginaryNumber() { val expected = ComplexNumber(real = -1.0) val actual = exponential(ComplexNumber(imag = PI)) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testExponentialOfZero() { val expected = ComplexNumber(real = 1.0) val actual = exponential(ComplexNumber()) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testExponentialOfPurelyRealNumber() { val expected = ComplexNumber(real = E) val actual = exponential(ComplexNumber(real = 1.0)) assertComplexNumbersEqual(expected, actual) } @Ignore @Test fun testExponentialOfANumberWithRealAndImaginaryPart() { val expected = ComplexNumber(real = -2.0) val actual = exponential(ComplexNumber(real = ln(2.0), imag = PI)) assertComplexNumbersEqual(expected, actual) } } ================================================ FILE: exercises/practice/crypto-square/.docs/instructions.md ================================================ # Instructions Implement the classic method for composing secret messages called a square code. Given an English text, output the encoded version of that text. First, the input is normalized: the spaces and punctuation are removed from the English text and the message is down-cased. Then, the normalized characters are broken into rows. These rows can be regarded as forming a rectangle when printed with intervening newlines. For example, the sentence ```text "If man was meant to stay on the ground, god would have given us roots." ``` is normalized to: ```text "ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots" ``` The plaintext should be organized into a rectangle as square as possible. The size of the rectangle should be decided by the length of the message. If `c` is the number of columns and `r` is the number of rows, then for the rectangle `r` x `c` find the smallest possible integer `c` such that: - `r * c >= length of message`, - and `c >= r`, - and `c - r <= 1`. Our normalized text is 54 characters long, dictating a rectangle with `c = 8` and `r = 7`: ```text "ifmanwas" "meanttos" "tayonthe" "groundgo" "dwouldha" "vegivenu" "sroots " ``` The coded message is obtained by reading down the columns going left to right. The message above is coded as: ```text "imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau" ``` Output the encoded text in chunks that fill perfect rectangles `(r X c)`, with `c` chunks of `r` length, separated by spaces. For phrases that are `n` characters short of the perfect rectangle, pad each of the last `n` chunks with a single trailing space. ```text "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " ``` Notice that were we to stack these, we could visually decode the ciphertext back in to the original message: ```text "imtgdvs" "fearwer" "mayoogo" "anouuio" "ntnnlvt" "wttddes" "aohghn " "sseoau " ``` ================================================ FILE: exercises/practice/crypto-square/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/CryptoSquare.kt" ], "test": [ "src/test/kotlin/CryptoSquareTest.kt" ], "example": [ ".meta/src/reference/kotlin/CryptoSquare.kt" ] }, "blurb": "Implement the classic method for composing secret messages called a square code.", "source": "J Dalbey's Programming Practice problems", "source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html" } ================================================ FILE: exercises/practice/crypto-square/.meta/src/reference/kotlin/CryptoSquare.kt ================================================ import kotlin.math.sqrt object CryptoSquare { fun ciphertext(plaintext: String): String { val sanitized = plaintext.filter { it.isLetterOrDigit() }.lowercase() if (sanitized.isEmpty()) { return "" } val (cols, rows) = calcSquare(sanitized.length) return (0 until cols * rows) .map { i -> (i % rows) * cols + (i / rows) } .map { cursor -> if (cursor < sanitized.length) sanitized[cursor] else ' ' } .joinToString("") .chunked(rows) .joinToString(" ") } private fun calcSquare(size: Int): Pair { val sq = sqrt(size.toDouble()).toInt() return when { sq * sq >= size -> Pair(sq, sq) // 9 => 3 * 3 (sq + 1) * sq >= size -> Pair(sq + 1, sq) // 54 => 8 * 7 else -> Pair(sq + 1, sq + 1) // 8 => 3 * 3 } } } ================================================ FILE: exercises/practice/crypto-square/.meta/tests.toml ================================================ [canonical-tests] # empty plaintext results in an empty ciphertext "407c3837-9aa7-4111-ab63-ec54b58e8e9f" = true # Lowercase "64131d65-6fd9-4f58-bdd8-4a2370fb481d" = true # Remove spaces "63a4b0ed-1e3c-41ea-a999-f6f26ba447d6" = true # Remove punctuation "1b5348a1-7893-44c1-8197-42d48d18756c" = true # 9 character plaintext results in 3 chunks of 3 characters "8574a1d3-4a08-4cec-a7c7-de93a164f41a" = true # 8 character plaintext results in 3 chunks, the last one with a trailing space "a65d3fa1-9e09-43f9-bcec-7a672aec3eae" = true # 54 character plaintext results in 7 chunks, the last two with trailing spaces "fbcb0c6d-4c39-4a31-83f6-c473baa6af80" = true ================================================ FILE: exercises/practice/crypto-square/.meta/version ================================================ 3.2.0 ================================================ FILE: exercises/practice/crypto-square/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/crypto-square/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/crypto-square/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/crypto-square/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/crypto-square/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/crypto-square/src/main/kotlin/CryptoSquare.kt ================================================ object CryptoSquare { fun ciphertext(plaintext: String): String { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/crypto-square/src/test/kotlin/CryptoSquareTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class CryptoSquareTest { @Test fun `empty plaintext results in empty ciphertext`() { val plaintext = "" val expectedOutput = "" assertEquals(expectedOutput, CryptoSquare.ciphertext(plaintext)) } @Ignore @Test fun `letters are lower cased during encryption`() { val plaintext = "A" val expectedOutput = "a" assertEquals(expectedOutput, CryptoSquare.ciphertext(plaintext)) } @Ignore @Test fun `spaces are removed during encryption`() { val plaintext = " b " val expectedOutput = "b" assertEquals(expectedOutput, CryptoSquare.ciphertext(plaintext)) } @Ignore @Test fun `punctuation is removed during encryption`() { val plaintext = "@1,%!" val expectedOutput = "1" assertEquals(expectedOutput, CryptoSquare.ciphertext(plaintext)) } @Ignore @Test fun `nine character plaintext results in three chunks of three characters`() { val plaintext = "This is fun!" val expectedOutput = "tsf hiu isn" assertEquals(expectedOutput, CryptoSquare.ciphertext(plaintext)) } @Ignore @Test fun `eight character plaintext results in three chunks with a trailing space`() { val plaintext = "Chill out." val expectedOutput = "clu hlt io " assertEquals(expectedOutput, CryptoSquare.ciphertext(plaintext)) } @Ignore @Test fun `fifty four character plaintext results in seven chunks with trailing spaces`() { val plaintext = "If man was meant to stay on the ground, god would have given us roots." val expectedOutput = "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " assertEquals(expectedOutput, CryptoSquare.ciphertext(plaintext)) } } ================================================ FILE: exercises/practice/custom-set/.docs/instructions.md ================================================ # Instructions Create a custom set type. Sometimes it is necessary to define a custom data structure of some type, like a set. In this exercise you will define your own set. How it works internally doesn't matter, as long as it behaves like a set of unique elements. ================================================ FILE: exercises/practice/custom-set/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/CustomSet.kt" ], "test": [ "src/test/kotlin/CustomSetTest.kt" ], "example": [ ".meta/src/reference/kotlin/CustomSet.kt" ] }, "blurb": "Create a custom set type." } ================================================ FILE: exercises/practice/custom-set/.meta/src/reference/kotlin/CustomSet.kt ================================================ class CustomSet(vararg elements: Int) { private val set: MutableSet = elements.toMutableSet() fun isEmpty(): Boolean = set.isEmpty() fun isSubset(other: CustomSet): Boolean = other.set.containsAll(set) fun isDisjoint(other: CustomSet): Boolean = set.intersect(other.set).isEmpty() fun contains(other: Int): Boolean = set.contains(other) fun intersection(other: CustomSet): CustomSet = apply { set.retainAll(other.set) } fun add(other: Int) = set.add(other) override fun equals(other: Any?): Boolean = (other != null && other is CustomSet && set == other.set) operator fun plus(other: CustomSet): CustomSet = apply { set.addAll(other.set) } operator fun minus(other: CustomSet): CustomSet = apply { set.removeAll(other.set) } } ================================================ FILE: exercises/practice/custom-set/.meta/tests.toml ================================================ [canonical-tests] # sets with no elements are empty "20c5f855-f83a-44a7-abdd-fe75c6cf022b" = true # sets with elements are not empty "d506485d-5706-40db-b7d8-5ceb5acf88d2" = true # nothing is contained in an empty set "759b9740-3417-44c3-8ca3-262b3c281043" = true # when the element is in the set "f83cd2d1-2a85-41bc-b6be-80adbff4be49" = true # when the element is not in the set "93423fc0-44d0-4bc0-a2ac-376de8d7af34" = true # empty set is a subset of another empty set "c392923a-637b-4495-b28e-34742cd6157a" = true # empty set is a subset of non-empty set "5635b113-be8c-4c6f-b9a9-23c485193917" = true # non-empty set is not a subset of empty set "832eda58-6d6e-44e2-92c2-be8cf0173cee" = true # set is a subset of set with exact same elements "c830c578-8f97-4036-b082-89feda876131" = true # set is a subset of larger set with same elements "476a4a1c-0fd1-430f-aa65-5b70cbc810c5" = true # set is not a subset of set that does not contain its elements "d2498999-3e46-48e4-9660-1e20c3329d3d" = true # the empty set is disjoint with itself "7d38155e-f472-4a7e-9ad8-5c1f8f95e4cc" = true # empty set is disjoint with non-empty set "7a2b3938-64b6-4b32-901a-fe16891998a6" = true # non-empty set is disjoint with empty set "589574a0-8b48-48ea-88b0-b652c5fe476f" = true # sets are not disjoint if they share an element "febeaf4f-f180-4499-91fa-59165955a523" = true # sets are disjoint if they share no elements "0de20d2f-c952-468a-88c8-5e056740f020" = true # empty sets are equal "4bd24adb-45da-4320-9ff6-38c044e9dff8" = true # empty set is not equal to non-empty set "f65c0a0e-6632-4b2d-b82c-b7c6da2ec224" = true # non-empty set is not equal to empty set "81e53307-7683-4b1e-a30c-7e49155fe3ca" = true # sets with the same elements are equal "d57c5d7c-a7f3-48cc-a162-6b488c0fbbd0" = true # sets with different elements are not equal "dd61bafc-6653-42cc-961a-ab071ee0ee85" = true # set is not equal to larger set with same elements "06059caf-9bf4-425e-aaff-88966cb3ea14" = true # add to empty set "8a677c3c-a658-4d39-bb88-5b5b1a9659f4" = true # add to non-empty set "0903dd45-904d-4cf2-bddd-0905e1a8d125" = true # adding an existing element does not change the set "b0eb7bb7-5e5d-4733-b582-af771476cb99" = true # intersection of two empty sets is an empty set "893d5333-33b8-4151-a3d4-8f273358208a" = true # intersection of an empty set and non-empty set is an empty set "d739940e-def2-41ab-a7bb-aaf60f7d782c" = true # intersection of a non-empty set and an empty set is an empty set "3607d9d8-c895-4d6f-ac16-a14956e0a4b7" = true # intersection of two sets with no shared elements is an empty set "b5120abf-5b5e-41ab-aede-4de2ad85c34e" = true # intersection of two sets with shared elements is a set of the shared elements "af21ca1b-fac9-499c-81c0-92a591653d49" = true # difference of two empty sets is an empty set "c5e6e2e4-50e9-4bc2-b89f-c518f015b57e" = true # difference of empty set and non-empty set is an empty set "2024cc92-5c26-44ed-aafd-e6ca27d6fcd2" = true # difference of a non-empty set and an empty set is the non-empty set "e79edee7-08aa-4c19-9382-f6820974b43e" = true # difference of two non-empty sets is a set of elements that are only in the first set "c5ac673e-d707-4db5-8d69-7082c3a5437e" = true # union of empty sets is an empty set "c45aed16-5494-455a-9033-5d4c93589dc6" = true # union of an empty set and non-empty set is the non-empty set "9d258545-33c2-4fcb-a340-9f8aa69e7a41" = true # union of a non-empty set and empty set is the non-empty set "3aade50c-80c7-4db8-853d-75bac5818b83" = true # union of non-empty sets contains all unique elements "a00bb91f-c4b4-4844-8f77-c73e2e9df77c" = true ================================================ FILE: exercises/practice/custom-set/.meta/version ================================================ 1.3.0 ================================================ FILE: exercises/practice/custom-set/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/custom-set/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/custom-set/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/custom-set/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/custom-set/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/custom-set/src/main/kotlin/CustomSet.kt ================================================ class CustomSet() { // TODO: implement proper constructor fun isEmpty(): Boolean { TODO("Implement this function to complete the task") } fun isSubset(other: CustomSet): Boolean { TODO("Implement this function to complete the task") } fun isDisjoint(other: CustomSet): Boolean { TODO("Implement this function to complete the task") } fun contains(other: Int): Boolean { TODO("Implement this function to complete the task") } fun intersection(other: CustomSet): CustomSet { TODO("Implement this function to complete the task") } fun add(other: Int) { TODO("Implement this function to complete the task") } override fun equals(other: Any?): Boolean { TODO("Implement this function to complete the task") } operator fun plus(other: CustomSet): CustomSet { TODO("Implement this function to complete the task") } operator fun minus(other: CustomSet): CustomSet { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/custom-set/src/test/kotlin/CustomSetTest.kt ================================================ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertNotEquals import kotlin.test.assertTrue import kotlin.test.Ignore class CustomSetTest { @Test fun `sets with no elements are empty`() { val sut = CustomSet() assertTrue(sut.isEmpty()) } @Ignore @Test fun `sets with elements are not empty`() { val sut = CustomSet(1) assertFalse(sut.isEmpty()) } @Ignore @Test fun `nothing is contained in an empty set`() { val sut = CustomSet() assertFalse(sut.contains(1)) } @Ignore @Test fun `when the element is in the set`() { val sut = CustomSet(1, 2, 3) assertTrue(sut.contains(1)) } @Ignore @Test fun `when the element is not in the set`() { val sut = CustomSet(1, 2, 3) assertFalse(sut.contains(4)) } @Ignore @Test fun `empty set is a subset of another empty set`() { val set1 = CustomSet() val set2 = CustomSet() assertTrue(set1.isSubset(set2)) } @Ignore @Test fun `empty set is a subset of non empty set`() { val set1 = CustomSet() val set2 = CustomSet(1) assertTrue(set1.isSubset(set2)) } @Ignore @Test fun `non empty set is not a subset of empty set`() { val set1 = CustomSet(1) val set2 = CustomSet() assertFalse(set1.isSubset(set2)) } @Ignore @Test fun `set is a subset of set with exact same elements`() { val set1 = CustomSet(1, 2, 3) val set2 = CustomSet(1, 2, 3) assertTrue(set1.isSubset(set2)) } @Ignore @Test fun `set is a subset of larger set with same elements`() { val set1 = CustomSet(1, 2, 3) val set2 = CustomSet(4, 1, 2, 3) assertTrue(set1.isSubset(set2)) } @Ignore @Test fun `set is not a subset of set that does not contain its elements`() { val set1 = CustomSet(1, 2, 3) val set2 = CustomSet(4, 1, 3) assertFalse(set1.isSubset(set2)) } @Ignore @Test fun `the empty set is disjoint with itself`() { val set1 = CustomSet() val set2 = CustomSet() assertTrue(set1.isDisjoint(set2)) } @Ignore @Test fun `empty set is disjoint with non empty set`() { val set1 = CustomSet() val set2 = CustomSet(1) assertTrue(set1.isDisjoint(set2)) } @Ignore @Test fun `non empty set is disjoint with empty set`() { val set1 = CustomSet(1) val set2 = CustomSet() assertTrue(set1.isDisjoint(set2)) } @Ignore @Test fun `sets are not disjoint if they share an element`() { val set1 = CustomSet(1, 2) val set2 = CustomSet(2, 3) assertFalse(set1.isDisjoint(set2)) } @Ignore @Test fun `sets are disjoint if they share no elements`() { val set1 = CustomSet(1, 2) val set2 = CustomSet(3, 4) assertTrue(set1.isDisjoint(set2)) } @Ignore @Test fun `empty sets are equal`() { val set1 = CustomSet() val set2 = CustomSet() assertEquals(set1, set2) } @Ignore @Test fun `empty set is not equal to non empty set`() { val set1 = CustomSet() val set2 = CustomSet(1, 2, 3) assertNotEquals(set1, set2) } @Ignore @Test fun `non empty set is not equal to empty set`() { val set1 = CustomSet(1, 2, 3) val set2 = CustomSet() assertNotEquals(set1, set2) } @Ignore @Test fun `sets with the same elements are equal`() { val set1 = CustomSet(1, 2) val set2 = CustomSet(2, 1) assertEquals(set1, set2) } @Ignore @Test fun `sets with different elements are not equal`() { val set1 = CustomSet(1, 2, 3) val set2 = CustomSet(1, 2, 4) assertNotEquals(set1, set2) } @Ignore @Test fun `set is not equal to larger set with same elements`() { val set1 = CustomSet(1, 2, 3) val set2 = CustomSet(1, 2, 3, 4) assertNotEquals(set1, set2) } @Ignore @Test fun `add to empty set`() { val sut = CustomSet() val expected = CustomSet(3) sut.add(3) assertEquals(expected, sut) } @Ignore @Test fun `add to non empty set`() { val sut = CustomSet(1, 2, 4) val expected = CustomSet(1, 2, 3, 4) sut.add(3) assertEquals(expected, sut) } @Ignore @Test fun `adding an existing element does not change the set`() { val sut = CustomSet(1, 2, 3) val expected = CustomSet(1, 2, 3) sut.add(3) assertEquals(expected, sut) } @Ignore @Test fun `intersection of two empty sets is an empty set`() { val set1 = CustomSet() val set2 = CustomSet() val expected = CustomSet() assertEquals(expected, set1.intersection(set2)) } @Ignore @Test fun `intersection of an empty set and non empty set is an empty set`() { val set1 = CustomSet() val set2 = CustomSet(3, 2, 5) val expected = CustomSet() assertEquals(expected, set1.intersection(set2)) } @Ignore @Test fun `intersection of a non empty set and an empty set is an empty set`() { val set1 = CustomSet(1, 2, 3, 4) val set2 = CustomSet() val expected = CustomSet() assertEquals(expected, set1.intersection(set2)) } @Ignore @Test fun `intersection of two sets with no shared elements is an empty set`() { val set1 = CustomSet(1, 2, 3) val set2 = CustomSet(4, 5, 6) val expected = CustomSet() assertEquals(expected, set1.intersection(set2)) } @Ignore @Test fun `intersection of two sets with shared elements is a set of the shared elements`() { val set1 = CustomSet(1, 2, 3, 4) val set2 = CustomSet(3, 2, 5) val expected = CustomSet(2, 3) assertEquals(expected, set1.intersection(set2)) } @Ignore @Test fun `difference of two empty sets is an empty set`() { val set1 = CustomSet() val set2 = CustomSet() val expected = CustomSet() assertEquals(expected, set1 - set2) } @Ignore @Test fun `difference of empty set and non empty set is an empty set`() { val set1 = CustomSet() val set2 = CustomSet(3, 2, 5) val expected = CustomSet() assertEquals(expected, set1 - set2) } @Ignore @Test fun `difference of a non empty set and an empty set is the non empty set`() { val set1 = CustomSet(1, 2, 3, 4) val set2 = CustomSet() val expected = CustomSet(1, 2, 3, 4) assertEquals(expected, set1 - set2) } @Ignore @Test fun `difference of two non empty sets is a set of elements that are only in the first set`() { val set1 = CustomSet(3, 2, 1) val set2 = CustomSet(2, 4) val expected = CustomSet(1, 3) assertEquals(expected, set1 - set2) } @Ignore @Test fun `union of empty sets is an empty set`() { val set1 = CustomSet() val set2 = CustomSet() val expected = CustomSet() assertEquals(expected, set1 + set2) } @Ignore @Test fun `union of an empty set and non empty set is the non empty set`() { val set1 = CustomSet() val set2 = CustomSet(2) val expected = CustomSet(2) assertEquals(expected, set1 + set2) } @Ignore @Test fun `union of a non empty set and empty set is the non empty set`() { val set1 = CustomSet(1, 3) val set2 = CustomSet() val expected = CustomSet(1, 3) assertEquals(expected, set1 + set2) } @Ignore @Test fun `union of non empty sets contains all unique elements`() { val set1 = CustomSet(1, 3) val set2 = CustomSet(2, 3) val expected = CustomSet(3, 2, 1) assertEquals(expected, set1 + set2) } } ================================================ FILE: exercises/practice/darts/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "40396c67-efdd-4031-bbfd-12e92e7448c8", "slug": "hypot-for-radius", "title": "hypot for radius", "blurb": "Use the hypot function to get the radius of the throw.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/darts/.approaches/hypot-for-radius/content.md ================================================ # `hypot` for radius ```kotlin import kotlin.math.hypot object Darts { private const val innerRing = 1.0 private const val middleRing = 5.0 private const val outerRing = 10.0 fun score(x: Number, y: Number): Int { val toss = hypot(x.toDouble(), y.toDouble()) fun throwWithin(ring: Double) = toss <= ring if (throwWithin(innerRing)) return 10 if (throwWithin(middleRing)) return 5 if (throwWithin(outerRing)) return 1 return 0 } } ``` An [object declaration][object] is used to define `Darts` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `score` method. The object defines [private][visibility] [`const`][const] [val][variables]s for the rings. The `const` values are given meaningful names instead of using the float literals as [magic numbers][magic-numbers]. A `val` is immutable, as is a `const`. A `const` `val` means that the value of the `val` is known at compile time. The [`hypot`][hypot] function is used to calculate the [radius][radius] of the dart throw from the `x` and `y` coordinates. The `throwWithin` function returns if the radius is within the ring passed in. Due to the naming of the function and varables, the `if` statements read much like natural language. The `throwWithin` function is passed the ring. If it returns `true`, then the function returns with the score for throwing within that ring. If the throw is not within a defined ring, then the function returns `0`. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [visibility]: https://kotlinlang.org/docs/visibility-modifiers.html [const]: https://www.geeksforgeeks.org/whats-the-difference-between-const-and-val-in-kotlin/ [variables]: https://kotlinlang.org/docs/basic-syntax.html#variables [magic-numbers]: https://en.wikipedia.org/wiki/Magic_number_(programming) [hypot]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/hypot.html [radius]: https://www.mathopenref.com/coordbasiccircle.html ================================================ FILE: exercises/practice/darts/.approaches/hypot-for-radius/snippet.txt ================================================ val toss = hypot(x.toDouble(), y.toDouble()) fun throwWithin(ring: Double) = toss <= ring if (throwWithin(innerRing)) return 10 if (throwWithin(middleRing)) return 5 if (throwWithin(outerRing)) return 1 return 0 ================================================ FILE: exercises/practice/darts/.approaches/introduction.md ================================================ # Introduction There are several ways to solve Darts. One approach is to use the [`hypot`][hypot] function to get the [radius][radius] of the throw. ## Approach: `hypot` for radius ```kotlin import kotlin.math.hypot object Darts { private const val innerRing = 1.0 private const val middleRing = 5.0 private const val outerRing = 10.0 fun score(x: Number, y: Number): Int { val toss = hypot(x.toDouble(), y.toDouble()) fun throwWithin(ring: Double) = toss <= ring if (throwWithin(innerRing)) return 10 if (throwWithin(middleRing)) return 5 if (throwWithin(outerRing)) return 1 return 0 } } ``` For more information, check the [`hypot` for radius approach][approach-hypot-for-radius]. [approach-hypot-for-radius]: https://exercism.org/tracks/kotlin/exercises/darts/approaches/hypot-for-radius [hypot]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/hypot.html [radius]: https://www.mathopenref.com/coordbasiccircle.html ================================================ FILE: exercises/practice/darts/.docs/instructions.md ================================================ # Instructions Calculate the points scored in a single toss of a Darts game. [Darts][darts] is a game where players throw darts at a [target][darts-target]. In our particular instance of the game, the target rewards 4 different amounts of points, depending on where the dart lands: ![Our dart scoreboard with values from a complete miss to a bullseye](https://assets.exercism.org/images/exercises/darts/darts-scoreboard.svg) - If the dart lands outside the target, player earns no points (0 points). - If the dart lands in the outer circle of the target, player earns 1 point. - If the dart lands in the middle circle of the target, player earns 5 points. - If the dart lands in the inner circle of the target, player earns 10 points. The outer circle has a radius of 10 units (this is equivalent to the total radius for the entire target), the middle circle a radius of 5 units, and the inner circle a radius of 1. Of course, they are all centered at the same point — that is, the circles are [concentric][] defined by the coordinates (0, 0). Given a point in the target (defined by its [Cartesian coordinates][cartesian-coordinates] `x` and `y`, where `x` and `y` are [real][real-numbers]), calculate the correct score earned by a dart landing at that point. ## Credit The scoreboard image was created by [habere-et-dispertire][habere-et-dispertire] using [Inkscape][inkscape]. [darts]: https://en.wikipedia.org/wiki/Darts [darts-target]: https://en.wikipedia.org/wiki/Darts#/media/File:Darts_in_a_dartboard.jpg [concentric]: https://mathworld.wolfram.com/ConcentricCircles.html [cartesian-coordinates]: https://www.mathsisfun.com/data/cartesian-coordinates.html [real-numbers]: https://www.mathsisfun.com/numbers/real-numbers.html [habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire [inkscape]: https://en.wikipedia.org/wiki/Inkscape ================================================ FILE: exercises/practice/darts/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Darts.kt" ], "test": [ "src/test/kotlin/DartsTest.kt" ], "example": [ ".meta/src/reference/kotlin/Darts.kt" ] }, "blurb": "Calculate the points scored in a single toss of a Darts game.", "source": "Inspired by an exercise created by a professor Della Paolera in Argentina" } ================================================ FILE: exercises/practice/darts/.meta/src/reference/kotlin/Darts.kt ================================================ import kotlin.math.pow import kotlin.math.sqrt object Darts { /** Return the correct amount earned by a dart's landing position. */ fun score(x: Number, y: Number): Int { val r = sqrt(x.toDouble().pow(2.0) + y.toDouble().pow(2.0)) // Pythagoras return when { r <= 1 -> 10 r <= 5 -> 5 r <= 10 -> 1 else -> 0 } } } ================================================ FILE: exercises/practice/darts/.meta/tests.toml ================================================ [canonical-tests] # Missed target "9033f731-0a3a-4d9c-b1c0-34a1c8362afb" = true # On the outer circle "4c9f6ff4-c489-45fd-be8a-1fcb08b4d0ba" = true # On the middle circle "14378687-ee58-4c9b-a323-b089d5274be8" = true # On the inner circle "849e2e63-85bd-4fed-bc3b-781ae962e2c9" = true # Exactly on centre "1c5ffd9f-ea66-462f-9f06-a1303de5a226" = true # Near the centre "b65abce3-a679-4550-8115-4b74bda06088" = true # Just within the inner circle "66c29c1d-44f5-40cf-9927-e09a1305b399" = true # Just outside the inner circle "d1012f63-c97c-4394-b944-7beb3d0b141a" = true # Just within the middle circle "ab2b5666-b0b4-49c3-9b27-205e790ed945" = true # Just outside the middle circle "70f1424e-d690-4860-8caf-9740a52c0161" = true # Just within the outer circle "a7dbf8db-419c-4712-8a7f-67602b69b293" = true # Just outside the outer circle "e0f39315-9f9a-4546-96e4-a9475b885aa7" = true # Asymmetric position between the inner and middle circles "045d7d18-d863-4229-818e-b50828c75d19" = true ================================================ FILE: exercises/practice/darts/.meta/version ================================================ 2.2.0 ================================================ FILE: exercises/practice/darts/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/darts/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/darts/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/darts/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/darts/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/darts/src/main/kotlin/Darts.kt ================================================ object Darts { fun score(x: Any, y: Any /* choose proper types! */): Int { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/darts/src/test/kotlin/DartsTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class DartsTest { @Test fun `missed target`() = assertEquals(0, Darts.score(-9, 9)) @Ignore @Test fun `on the outer circle`() = assertEquals(1, Darts.score(0, 10)) @Ignore @Test fun `on the middle circle`() = assertEquals(5, Darts.score(-5, 0)) @Ignore @Test fun `on the inner circle`() = assertEquals(10, Darts.score(0, -1)) @Ignore @Test fun `exactly on centre`() = assertEquals(10, Darts.score(0, 0)) @Ignore @Test fun `near the centre`() = assertEquals(10, Darts.score(-0.1, -0.1)) @Ignore @Test fun `just within the inner circle`() = assertEquals(10, Darts.score(0.7, 0.7)) @Ignore @Test fun `just outside the inner circle`() = assertEquals(5, Darts.score(0.8, -0.8)) @Ignore @Test fun `just within the middle circle`() = assertEquals(5, Darts.score(-3.5, 3.5)) @Ignore @Test fun `just outside the middle circle`() = assertEquals(1, Darts.score(-3.6, -3.6)) @Ignore @Test fun `just within the outer circle`() = assertEquals(1, Darts.score(-7.0, 7.0)) @Ignore @Test fun `just outside the outer circle`() = assertEquals(0, Darts.score(7.1, -7.1)) @Ignore @Test fun `asymmetric position between the inner and middle circles`() = assertEquals(5, Darts.score(0.5, -4)) } ================================================ FILE: exercises/practice/diamond/.docs/instructions.md ================================================ # Instructions The diamond kata takes as its input a letter, and outputs it in a diamond shape. Given a letter, it prints a diamond starting with 'A', with the supplied letter at the widest point. ## Requirements - The first row contains one 'A'. - The last row contains one 'A'. - All rows, except the first and last, have exactly two identical letters. - All rows have as many trailing spaces as leading spaces. (This might be 0). - The diamond is horizontally symmetric. - The diamond is vertically symmetric. - The diamond has a square shape (width equals height). - The letters form a diamond shape. - The top half has the letters in ascending order. - The bottom half has the letters in descending order. - The four corners (containing the spaces) are triangles. ## Examples In the following examples, spaces are indicated by `·` characters. Diamond for letter 'A': ```text A ``` Diamond for letter 'C': ```text ··A·· ·B·B· C···C ·B·B· ··A·· ``` Diamond for letter 'E': ```text ····A···· ···B·B··· ··C···C·· ·D·····D· E·······E ·D·····D· ··C···C·· ···B·B··· ····A···· ``` ================================================ FILE: exercises/practice/diamond/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/DiamondPrinter.kt" ], "test": [ "src/test/kotlin/DiamondPrinterTest.kt" ], "example": [ ".meta/src/reference/kotlin/DiamondPrinter.kt" ] }, "blurb": "Given a letter, print a diamond starting with 'A' with the supplied letter at the widest point.", "source": "Seb Rose", "source_url": "https://web.archive.org/web/20220807163751/http://claysnow.co.uk/recycling-tests-in-tdd/" } ================================================ FILE: exercises/practice/diamond/.meta/src/reference/kotlin/DiamondPrinter.kt ================================================ import java.util.* class DiamondPrinter { companion object { private const val A_INT = 'A'.code private fun blank(length: Int): String { return Collections.nCopies(length, " ").joinToString("") } } fun printToList(chr: Char): List { val nRows = 2 * (chr.code - A_INT) + 1 val result = mutableListOf() // Populate the top rows. for (nRow in 0 until (nRows + 1) / 2) { val rowChr = (A_INT + nRow).toChar() val leftHalfOfRow = blank((nRows - 1) / 2 - nRow) + rowChr + blank(nRow) val rightHalfOfRow = leftHalfOfRow.reversed().drop(1) val fullRow = "$leftHalfOfRow$rightHalfOfRow" result.add(fullRow) } // Populate the bottom rows by 'reflecting' all rows above the middle row. result.addAll(result.reversed().drop(1)) return result } } ================================================ FILE: exercises/practice/diamond/.meta/tests.toml ================================================ [canonical-tests] # Degenerate case with a single 'A' row "202fb4cc-6a38-4883-9193-a29d5cb92076" = true # Degenerate case with no row containing 3 distinct groups of spaces "bd6a6d78-9302-42e9-8f60-ac1461e9abae" = true # Smallest non-degenerate case with odd diamond side length "af8efb49-14ed-447f-8944-4cc59ce3fd76" = true # Smallest non-degenerate case with even diamond side length "e0c19a95-9888-4d05-86a0-fa81b9e70d1d" = true # Largest possible diamond "82ea9aa9-4c0e-442a-b07e-40204e925944" = true ================================================ FILE: exercises/practice/diamond/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/diamond/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/diamond/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/diamond/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/diamond/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/diamond/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/diamond/src/main/kotlin/DiamondPrinter.kt ================================================ class DiamondPrinter { } ================================================ FILE: exercises/practice/diamond/src/test/kotlin/DiamondPrinterTest.kt ================================================ import org.hamcrest.CoreMatchers.`is` import org.hamcrest.MatcherAssert.assertThat import org.junit.Before import org.junit.Ignore import org.junit.Test class DiamondPrinterTest { private lateinit var diamondPrinter: DiamondPrinter @Before fun setUp() { diamondPrinter = DiamondPrinter() } @Test fun testOneByOneDiamond() { val output = diamondPrinter.printToList('A') assertThat(output, `is`(listOf("A"))) } @Ignore @Test fun testTwoByTwoDiamond() { val output = diamondPrinter.printToList('B') assertThat(output, `is`(listOf( " A ", "B B", " A "))) } @Ignore @Test fun testThreeByThreeDiamond() { val output = diamondPrinter.printToList('C') assertThat(output, `is`(listOf( " A ", " B B ", "C C", " B B ", " A "))) } @Ignore @Test fun testFiveByFiveDiamond() { val output = diamondPrinter.printToList('E') assertThat(output, `is`(listOf( " A ", " B B ", " C C ", " D D ", "E E", " D D ", " C C ", " B B ", " A "))) } @Ignore @Test fun testFullDiamond() { val output = diamondPrinter.printToList('Z') assertThat(output, `is`(listOf( " A ", " B B ", " C C ", " D D ", " E E ", " F F ", " G G ", " H H ", " I I ", " J J ", " K K ", " L L ", " M M ", " N N ", " O O ", " P P ", " Q Q ", " R R ", " S S ", " T T ", " U U ", " V V ", " W W ", " X X ", " Y Y ", "Z Z", " Y Y ", " X X ", " W W ", " V V ", " U U ", " T T ", " S S ", " R R ", " Q Q ", " P P ", " O O ", " N N ", " M M ", " L L ", " K K ", " J J ", " I I ", " H H ", " G G ", " F F ", " E E ", " D D ", " C C ", " B B ", " A "))) } } ================================================ FILE: exercises/practice/difference-of-squares/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "862a595e-613f-4172-87f1-95c04e0051de", "slug": "formula", "title": "Formula", "blurb": "Use a formula to calculate a solution.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/difference-of-squares/.approaches/formula/content.md ================================================ # Use formula ```kotlin class Squares(private val input: Int) { fun squareOfSum() = (input * (input + 1) / 2).let { it * it } fun sumOfSquares() = (input * (input + 1) * ((input * 2) + 1)) / 6 fun difference() = squareOfSum() - sumOfSquares() } ``` A [`private`][visibility] [`val`][variables] is defined as the parameter for the primary [constructor][constructors]. In this solution a [formula][formula] is used to solve the `squareOfSum` and `sumOfSquares` methods. At the time of this writing the instructions state: >You are not expected to discover an efficient solution to this yourself from first principles; >research is allowed, indeed, encouraged. Finding the best algorithm for the problem is a key skill in software engineering. It is fine to search for an algorithm on the internet. This is also sometimes referred to as ["Google is your friend"][google-friend], although you don't have to search with Google. It is okay if you don't understand how the algorithm works. What is important is that it obviously is not introducing malware and that it passes the tests. Note that this avoids using [`pow`][pow] in `squareOfSum`, since multiplying a value by itself is usually more efficient than type-casting from `int `to `double` back to `int`. Instead, it uses the [`it`][it] keyword to refer to the value multiplied by itself in the [`let`][let] function. [constructors]: https://www.geeksforgeeks.org/kotlin-constructor/ [visibility]: https://kotlinlang.org/docs/visibility-modifiers.html [variables]: https://kotlinlang.org/docs/basic-syntax.html#variables [formula]: https://learnersbucket.com/examples/algorithms/difference-between-square-of-sum-of-numbers-and-sum-of-square-of-numbers/ [google-friend]: https://en.wiktionary.org/wiki/Google_is_your_friend [pow]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/pow.html [let]: https://kotlinlang.org/docs/scope-functions.html#let [it]: https://kotlinlang.org/docs/lambdas.html#it-implicit-name-of-a-single-parameter ================================================ FILE: exercises/practice/difference-of-squares/.approaches/formula/snippet.txt ================================================ class Squares(private val input: Int) { fun squareOfSum() = (input * (input + 1) / 2).let { it * it } fun sumOfSquares() = (input * (input + 1) * ((input * 2) + 1)) / 6 fun difference() = squareOfSum() - sumOfSquares() } ================================================ FILE: exercises/practice/difference-of-squares/.approaches/introduction.md ================================================ # Introduction There are various ways to solve Difference of Squares. One approach is to use a [formula][formula] to calculate the solution. ## Approach: Use formula ```kotlin class Squares(private val input: Int) { fun squareOfSum() = (input * (input + 1) / 2).let { it * it } fun sumOfSquares() = (input * (input + 1) * ((input * 2) + 1)) / 6 fun difference() = squareOfSum() - sumOfSquares() } ``` For more information, check the [formula approach][approach-formula]. [formula]: https://learnersbucket.com/examples/algorithms/difference-between-square-of-sum-of-numbers-and-sum-of-square-of-numbers/ [approach-formula]: https://exercism.org/tracks/kotlin/exercises/difference-of-squares/approaches/formula ================================================ FILE: exercises/practice/difference-of-squares/.docs/instructions.md ================================================ # Instructions Find the difference between the square of the sum and the sum of the squares of the first N natural numbers. The square of the sum of the first ten natural numbers is (1 + 2 + ... + 10)² = 55² = 3025. The sum of the squares of the first ten natural numbers is 1² + 2² + ... + 10² = 385. Hence the difference between the square of the sum of the first ten natural numbers and the sum of the squares of the first ten natural numbers is 3025 - 385 = 2640. You are not expected to discover an efficient solution to this yourself from first principles; research is allowed, indeed, encouraged. Finding the best algorithm for the problem is a key skill in software engineering. ================================================ FILE: exercises/practice/difference-of-squares/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/DifferenceOfSquares.kt" ], "test": [ "src/test/kotlin/SquaresTest.kt" ], "example": [ ".meta/src/reference/kotlin/DifferenceOfSquares.kt" ] }, "blurb": "Find the difference between the square of the sum and the sum of the squares of the first N natural numbers.", "source": "Problem 6 at Project Euler", "source_url": "https://projecteuler.net/problem=6" } ================================================ FILE: exercises/practice/difference-of-squares/.meta/src/reference/kotlin/DifferenceOfSquares.kt ================================================ class Squares(private val max: Int) { private val range = 1..max fun sumOfSquares() = range.sumOf { it.squared() } fun squareOfSum() = range.sum().squared() fun difference() = squareOfSum() - sumOfSquares() private fun Int.squared() = this * this } ================================================ FILE: exercises/practice/difference-of-squares/.meta/tests.toml ================================================ [canonical-tests] # square of sum 1 "e46c542b-31fc-4506-bcae-6b62b3268537" = true # square of sum 5 "9b3f96cb-638d-41ee-99b7-b4f9c0622948" = true # square of sum 100 "54ba043f-3c35-4d43-86ff-3a41625d5e86" = true # sum of squares 1 "01d84507-b03e-4238-9395-dd61d03074b5" = true # sum of squares 5 "c93900cd-8cc2-4ca4-917b-dd3027023499" = true # sum of squares 100 "94807386-73e4-4d9e-8dec-69eb135b19e4" = true # difference of squares 1 "44f72ae6-31a7-437f-858d-2c0837adabb6" = true # difference of squares 5 "005cb2bf-a0c8-46f3-ae25-924029f8b00b" = true # difference of squares 100 "b1bf19de-9a16-41c0-a62b-1f02ecc0b036" = true ================================================ FILE: exercises/practice/difference-of-squares/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/difference-of-squares/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/difference-of-squares/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/difference-of-squares/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/difference-of-squares/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/difference-of-squares/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/difference-of-squares/src/main/kotlin/DifferenceOfSquares.kt ================================================ class Squares { //TODO: implement proper constructor fun sumOfSquares() { TODO("Implement the function to complete the task") } fun squareOfSum() { TODO("Implement the function to complete the task") } fun difference() { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/difference-of-squares/src/test/kotlin/SquaresTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class SquaresTest { @Test fun squareOfSum1() { assertEquals(1, Squares(1).squareOfSum()) } @Ignore @Test fun squareOfSum5() { assertEquals(225, Squares(5).squareOfSum()) } @Ignore @Test fun squareOfSum100() { assertEquals(25502500, Squares(100).squareOfSum()) } @Ignore @Test fun sumOfSquares1() { assertEquals(1, Squares(1).sumOfSquares()) } @Ignore @Test fun sumOfSquares5() { assertEquals(55, Squares(5).sumOfSquares()) } @Ignore @Test fun sumOfSquares100() { assertEquals(338350, Squares(100).sumOfSquares()) } @Ignore @Test fun differenceOfSquares1() { assertEquals(0, Squares(1).difference()) } @Ignore @Test fun differenceOfSquares5() { assertEquals(170, Squares(5).difference()) } @Ignore @Test fun differenceOfSquares100() { assertEquals(25164150, Squares(100).difference()) } } ================================================ FILE: exercises/practice/diffie-hellman/.docs/instructions.md ================================================ # Instructions Diffie-Hellman key exchange. Alice and Bob use Diffie-Hellman key exchange to share secrets. They start with prime numbers, pick private keys, generate and share public keys, and then generate a shared secret key. ## Step 0 The test program supplies prime numbers p and g. ## Step 1 Alice picks a private key, a, greater than 1 and less than p. Bob does the same to pick a private key b. ## Step 2 Alice calculates a public key A. A = gᵃ mod p Using the same p and g, Bob similarly calculates a public key B from his private key b. ## Step 3 Alice and Bob exchange public keys. Alice calculates secret key s. s = Bᵃ mod p Bob calculates s = Aᵇ mod p The calculations produce the same result! Alice and Bob now share secret s. ================================================ FILE: exercises/practice/diffie-hellman/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/DiffieHellman.kt" ], "test": [ "src/test/kotlin/DiffieHellmanTest.kt" ], "example": [ ".meta/src/reference/kotlin/DiffieHellman.kt" ] }, "blurb": "Diffie-Hellman key exchange.", "source": "Wikipedia, 1024 bit key from www.cryptopp.com/wiki.", "source_url": "https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange" } ================================================ FILE: exercises/practice/diffie-hellman/.meta/src/reference/kotlin/DiffieHellman.kt ================================================ import java.math.BigInteger import java.util.Random object DiffieHellman { fun privateKey(prime: BigInteger): BigInteger { val rnd = Random() var bi: BigInteger do { bi = BigInteger(prime.bitCount(), rnd) } while (bi == BigInteger.ZERO || bi.compareTo(prime) == 1) return bi } fun publicKey(p: BigInteger, g: BigInteger, privKey: BigInteger): BigInteger { return g.modPow(privKey, p) } fun secret(prime: BigInteger, publicKey: BigInteger, privateKey: BigInteger): BigInteger { return publicKey.modPow(privateKey, prime) } } ================================================ FILE: exercises/practice/diffie-hellman/.meta/tests.toml ================================================ [canonical-tests] # private key is in range 1 .. p "1b97bf38-4307-418e-bfd2-446ffc77588d" = true # private key is random "68b2a5f7-7755-44c3-97b2-d28d21f014a9" = true # can calculate public key using private key "b4161d8e-53a1-4241-ae8f-48cc86527f22" = true # can calculate secret using other party's public key "cd02ad45-3f52-4510-99cc-5161dad948a8" = true # key exchange "17f13c61-a111-4075-9a1f-c2d4636dfa60" = true ================================================ FILE: exercises/practice/diffie-hellman/.meta/version ================================================ 1.0.0 ================================================ FILE: exercises/practice/diffie-hellman/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/diffie-hellman/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/diffie-hellman/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/diffie-hellman/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/diffie-hellman/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/diffie-hellman/src/main/kotlin/DiffieHellman.kt ================================================ import java.math.BigInteger object DiffieHellman { fun privateKey(prime: BigInteger): BigInteger { TODO("Implement the function to complete the task") } fun publicKey(p: BigInteger, g: BigInteger, privKey: BigInteger): BigInteger { TODO("Implement the function to complete the task") } fun secret(prime: BigInteger, publicKey: BigInteger, privateKey: BigInteger): BigInteger { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/diffie-hellman/src/test/kotlin/DiffieHellmanTest.kt ================================================ import org.junit.Test import java.math.BigInteger import kotlin.test.Ignore import kotlin.test.assertEquals import kotlin.test.assertNotEquals import kotlin.test.assertTrue class DiffieHellmanTest { @Test fun `private key is in range from 1 to prime`() { val prime = 23.toBigInteger() (0..9).map { DiffieHellman.privateKey(prime) }.forEach { assertTrue(it >= BigInteger.ONE) assertTrue(it < prime) } } /** * Due to the nature of randomness, there is always a chance that this test fails. * Be sure to check the actual generated values. */ @Ignore @Test fun `private key is random`() { val prime = 7919.toBigInteger() val privateKeyA = DiffieHellman.privateKey(prime) val privateKeyB = DiffieHellman.privateKey(prime) assertNotEquals(privateKeyA, privateKeyB) } @Ignore @Test fun `calculate public key using private key`() { val primeA = 23.toBigInteger() val primeB = 5.toBigInteger() val privateKey = 6.toBigInteger() val expected = 8.toBigInteger() assertEquals(expected, DiffieHellman.publicKey(primeA, primeB, privateKey)) } @Ignore @Test fun `calculate secret using other party's public key`() { val prime = 23.toBigInteger() val publicKey = 19.toBigInteger() val privateKey = 6.toBigInteger() val expected = 2.toBigInteger() assertEquals(expected, DiffieHellman.secret(prime, publicKey, privateKey)) } @Ignore @Test fun `key exchange`() { val primeA = 23.toBigInteger() val primeB = 5.toBigInteger() val alicePrivateKey = DiffieHellman.privateKey(primeA) val bobPrivateKey = DiffieHellman.privateKey(primeB) val alicePublicKey = DiffieHellman.publicKey(primeA, primeB, alicePrivateKey) val bobPublicKey = DiffieHellman.publicKey(primeA, primeB, bobPrivateKey) val secretA = DiffieHellman.secret(primeA, bobPublicKey, alicePrivateKey) val secretB = DiffieHellman.secret(primeA, alicePublicKey, bobPrivateKey) assertEquals(secretA, secretB) } } ================================================ FILE: exercises/practice/dnd-character/.docs/instructions.md ================================================ # Instructions For a game of [Dungeons & Dragons][dnd], each player starts by generating a character they can play with. This character has, among other things, six abilities; strength, dexterity, constitution, intelligence, wisdom and charisma. These six abilities have scores that are determined randomly. You do this by rolling four 6-sided dice and recording the sum of the largest three dice. You do this six times, once for each ability. Your character's initial hitpoints are 10 + your character's constitution modifier. You find your character's constitution modifier by subtracting 10 from your character's constitution, divide by 2 and round down. Write a random character generator that follows the above rules. For example, the six throws of four dice may look like: - 5, 3, 1, 6: You discard the 1 and sum 5 + 3 + 6 = 14, which you assign to strength. - 3, 2, 5, 3: You discard the 2 and sum 3 + 5 + 3 = 11, which you assign to dexterity. - 1, 1, 1, 1: You discard the 1 and sum 1 + 1 + 1 = 3, which you assign to constitution. - 2, 1, 6, 6: You discard the 1 and sum 2 + 6 + 6 = 14, which you assign to intelligence. - 3, 5, 3, 4: You discard the 3 and sum 5 + 3 + 4 = 12, which you assign to wisdom. - 6, 6, 6, 6: You discard the 6 and sum 6 + 6 + 6 = 18, which you assign to charisma. Because constitution is 3, the constitution modifier is -4 and the hitpoints are 6. ~~~~exercism/note Most programming languages feature (pseudo-)random generators, but few programming languages are designed to roll dice. One such language is [Troll][troll]. [troll]: https://di.ku.dk/Ansatte/?pure=da%2Fpublications%2Ftroll-a-language-for-specifying-dicerolls(84a45ff0-068b-11df-825d-000ea68e967b)%2Fexport.html ~~~~ [dnd]: https://en.wikipedia.org/wiki/Dungeons_%26_Dragons ================================================ FILE: exercises/practice/dnd-character/.docs/introduction.md ================================================ # Introduction After weeks of anticipation, you and your friends get together for your very first game of [Dungeons & Dragons][dnd] (D&D). Since this is the first session of the game, each player has to generate a character to play with. The character's abilities are determined by rolling 6-sided dice, but where _are_ the dice? With a shock, you realize that your friends are waiting for _you_ to produce the dice; after all it was your idea to play D&D! Panicking, you realize you forgot to bring the dice, which would mean no D&D game. As you have some basic coding skills, you quickly come up with a solution: you'll write a program to simulate dice rolls. [dnd]: https://en.wikipedia.org/wiki/Dungeons_%26_Dragons ================================================ FILE: exercises/practice/dnd-character/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/DndCharacter.kt" ], "test": [ "src/test/kotlin/DndCharacterTest.kt" ], "example": [ ".meta/src/reference/kotlin/DndCharacter.kt" ] }, "blurb": "Randomly generate Dungeons & Dragons characters.", "source": "Simon Shine, Erik Schierboom", "source_url": "https://github.com/exercism/problem-specifications/issues/616#issuecomment-437358945" } ================================================ FILE: exercises/practice/dnd-character/.meta/src/reference/kotlin/DndCharacter.kt ================================================ import java.lang.Math.floorDiv import kotlin.random.Random class DndCharacter { val strength: Int = ability() val dexterity: Int = ability() val constitution: Int = ability() val intelligence: Int = ability() val wisdom: Int = ability() val charisma: Int = ability() val hitpoints: Int = 10 + modifier(constitution) companion object { fun ability(): Int = (1 .. 4).map { Random.nextInt(1,6) }.sorted().drop(1).sum() fun modifier(score: Int): Int = floorDiv(score - 10, 2) } } ================================================ FILE: exercises/practice/dnd-character/.meta/tests.toml ================================================ [canonical-tests] # ability modifier for score 3 is -4 "1e9ae1dc-35bd-43ba-aa08-e4b94c20fa37" = true # ability modifier for score 4 is -3 "cc9bb24e-56b8-4e9e-989d-a0d1a29ebb9c" = true # ability modifier for score 5 is -3 "5b519fcd-6946-41ee-91fe-34b4f9808326" = true # ability modifier for score 6 is -2 "dc2913bd-6d7a-402e-b1e2-6d568b1cbe21" = true # ability modifier for score 7 is -2 "099440f5-0d66-4b1a-8a10-8f3a03cc499f" = true # ability modifier for score 8 is -1 "cfda6e5c-3489-42f0-b22b-4acb47084df0" = true # ability modifier for score 9 is -1 "c70f0507-fa7e-4228-8463-858bfbba1754" = true # ability modifier for score 10 is 0 "6f4e6c88-1cd9-46a0-92b8-db4a99b372f7" = true # ability modifier for score 11 is 0 "e00d9e5c-63c8-413f-879d-cd9be9697097" = true # ability modifier for score 12 is +1 "eea06f3c-8de0-45e7-9d9d-b8cab4179715" = true # ability modifier for score 13 is +1 "9c51f6be-db72-4af7-92ac-b293a02c0dcd" = true # ability modifier for score 14 is +2 "94053a5d-53b6-4efc-b669-a8b5098f7762" = true # ability modifier for score 15 is +2 "8c33e7ca-3f9f-4820-8ab3-65f2c9e2f0e2" = true # ability modifier for score 16 is +3 "c3ec871e-1791-44d0-b3cc-77e5fb4cd33d" = true # ability modifier for score 17 is +3 "3d053cee-2888-4616-b9fd-602a3b1efff4" = true # ability modifier for score 18 is +4 "bafd997a-e852-4e56-9f65-14b60261faee" = true # random ability is within range "4f28f19c-2e47-4453-a46a-c0d365259c14" = true # random character is valid "385d7e72-864f-4e88-8279-81a7d75b04ad" = true # each ability is only calculated once "2ca77b9b-c099-46c3-a02c-0d0f68ffa0fe" = true ================================================ FILE: exercises/practice/dnd-character/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/dnd-character/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/dnd-character/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/dnd-character/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/dnd-character/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/dnd-character/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/dnd-character/src/main/kotlin/DndCharacter.kt ================================================ class DndCharacter { val strength: Int = TODO("Initialize value to complete the task") val dexterity: Int = TODO("Initialize value to complete the task") val constitution: Int = TODO("Initialize value to complete the task") val intelligence: Int = TODO("Initialize value to complete the task") val wisdom: Int = TODO("Initialize value to complete the task") val charisma: Int = TODO("Initialize value to complete the task") val hitpoints: Int = TODO("Initialize value to complete the task") companion object { fun ability(): Int { TODO("Implement the function to complete the task") } fun modifier(score: Int): Int { TODO("Implement the function to complete the task") } } } ================================================ FILE: exercises/practice/dnd-character/src/test/kotlin/DndCharacterTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue class DndCharacterTest { @Test fun `ability modifier for score 3 is n4`() = assertEquals(-4, DndCharacter.modifier(3)) @Ignore @Test fun `ability modifier for score 4 is n3`() = assertEquals(-3, DndCharacter.modifier(4)) @Ignore @Test fun `ability modifier for score 5 is n3`() = assertEquals(-3, DndCharacter.modifier(5)) @Ignore @Test fun `ability modifier for score 6 is n2`() = assertEquals(-2, DndCharacter.modifier(6)) @Ignore @Test fun `ability modifier for score 7 is n2`() = assertEquals(-2, DndCharacter.modifier(7)) @Ignore @Test fun `ability modifier for score 8 is n1`() = assertEquals(-1, DndCharacter.modifier(8)) @Ignore @Test fun `ability modifier for score 9 is n1`() = assertEquals(-1, DndCharacter.modifier(9)) @Ignore @Test fun `ability modifier for score 10 is 0`() = assertEquals(0, DndCharacter.modifier(10)) @Ignore @Test fun `ability modifier for score 11 is 0`() = assertEquals(0, DndCharacter.modifier(11)) @Ignore @Test fun `ability modifier for score 12 is 1`() = assertEquals(1, DndCharacter.modifier(12)) @Ignore @Test fun `ability modifier for score 13 is 1`() = assertEquals(1, DndCharacter.modifier(13)) @Ignore @Test fun `ability modifier for score 14 is 2`() = assertEquals(2, DndCharacter.modifier(14)) @Ignore @Test fun `ability modifier for score 15 is 2`() = assertEquals(2, DndCharacter.modifier(15)) @Ignore @Test fun `ability modifier for score 16 is 3`() = assertEquals(3, DndCharacter.modifier(16)) @Ignore @Test fun `ability modifier for score 17 is 3`() = assertEquals(3, DndCharacter.modifier(17)) @Ignore @Test fun `ability modifier for score 18 is 4`() = assertEquals(4, DndCharacter.modifier(18)) @Ignore @Test fun `random ability is within range`() { val score = DndCharacter.ability() assertTrue(score in (3..18)) } @Ignore @Test fun `random character is valid`() { with (DndCharacter()) { assertTrue(strength in (3..18)) assertTrue(dexterity in (3..18)) assertTrue(constitution in (3..18)) assertTrue(intelligence in (3..18)) assertTrue(wisdom in (3..18)) assertTrue(charisma in (3..18)) assertEquals(10 + DndCharacter.modifier(constitution), hitpoints) } } @Ignore @Test fun `each ability is only calculated once`() { val char = DndCharacter() assertTrue(char.strength == char.strength) } } ================================================ FILE: exercises/practice/dominoes/.docs/instructions.md ================================================ # Instructions Make a chain of dominoes. Compute a way to order a given set of domino stones so that they form a correct domino chain. In the chain, the dots on one half of a stone must match the dots on the neighboring half of an adjacent stone. Additionally, the dots on the halves of the stones without neighbors (the first and last stone) must match each other. For example given the stones `[2|1]`, `[2|3]` and `[1|3]` you should compute something like `[1|2] [2|3] [3|1]` or `[3|2] [2|1] [1|3]` or `[1|3] [3|2] [2|1]` etc, where the first and last numbers are the same. For stones `[1|2]`, `[4|1]` and `[2|3]` the resulting chain is not valid: `[4|1] [1|2] [2|3]`'s first and last numbers are not the same. 4 != 3 Some test cases may use duplicate stones in a chain solution, assume that multiple Domino sets are being used. ================================================ FILE: exercises/practice/dominoes/.docs/introduction.md ================================================ # Introduction In Toyland, the trains are always busy delivering treasures across the city, from shiny marbles to rare building blocks. The tracks they run on are made of colorful domino-shaped pieces, each marked with two numbers. For the trains to move, the dominoes must form a perfect chain where the numbers match. Today, an urgent delivery of rare toys is on hold. You've been handed a set of track pieces to inspect. If they can form a continuous chain, the train will be on its way, bringing smiles across Toyland. If not, the set will be discarded, and another will be tried. The toys are counting on you to solve this puzzle. Will the dominoes connect the tracks and send the train rolling, or will the set be left behind? ================================================ FILE: exercises/practice/dominoes/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Dominoes.kt" ], "test": [ "src/test/kotlin/DominoesTest.kt" ], "example": [ ".meta/src/reference/kotlin/Dominoes.kt" ] }, "blurb": "Make a chain of dominoes." } ================================================ FILE: exercises/practice/dominoes/.meta/src/reference/kotlin/Dominoes.kt ================================================ import java.util.* class ChainNotFoundException(msg: String) : RuntimeException(msg) data class Domino(val left: Int, val right: Int) object Dominoes { fun formChain(vararg inputDominoes: Domino): List = formChain(inputDominoes.toList()) fun formChain(inputDominoes: List): List { if (inputDominoes.isEmpty()) { return emptyList() } return formPartialChain(ArrayList(), inputDominoes) } private fun isValidChain(chain: ArrayList): Boolean { return isValidPartialChain(chain) && chain.first().left == chain.last().right } private fun isValidPartialChain(chain: ArrayList): Boolean { for (i in 0 until chain.size - 1) { if (chain[i].right != chain[i + 1].left) { return false } } return true } private fun formPartialChain(current: ArrayList, remaining: List): ArrayList { if (remaining.isEmpty()) { if (isValidChain(current)) { return current } else { throw ChainNotFoundException("No domino chain found.") } } remaining.indices.forEach { i -> val newRemaining = ArrayList(remaining) newRemaining.removeAt(i) val newChainA = ArrayList(current) newChainA.add(remaining[i]) val newChainB = ArrayList(current) newChainB.add(Domino(remaining[i].right, remaining[i].left)) if (isValidPartialChain(newChainA)) { try { return formPartialChain(newChainA, newRemaining) } catch (e: ChainNotFoundException) { //This path does not have a valid chain } } if (isValidPartialChain(newChainB)) { try { return formPartialChain(newChainB, newRemaining) } catch (e: ChainNotFoundException) { //This path doesn't have a valid chain } } } throw ChainNotFoundException("No domino chain found.") } } ================================================ FILE: exercises/practice/dominoes/.meta/tests.toml ================================================ [canonical-tests] # empty input = empty output "31a673f2-5e54-49fe-bd79-1c1dae476c9c" = true # singleton input = singleton output "4f99b933-367b-404b-8c6d-36d5923ee476" = true # singleton that can't be chained "91122d10-5ec7-47cb-b759-033756375869" = true # three elements "be8bc26b-fd3d-440b-8e9f-d698a0623be3" = true # can reverse dominoes "99e615c6-c059-401c-9e87-ad7af11fea5c" = true # can't be chained "51f0c291-5d43-40c5-b316-0429069528c9" = true # disconnected - simple "9a75e078-a025-4c23-8c3a-238553657f39" = true # disconnected - double loop "0da0c7fe-d492-445d-b9ef-1f111f07a301" = true # disconnected - single isolated "b6087ff0-f555-4ea0-a71c-f9d707c5994a" = true # need backtrack "2174fbdc-8b48-4bac-9914-8090d06ef978" = true # separate loops "167bb480-dfd1-4318-a20d-4f90adb4a09f" = true # nine elements "cd061538-6046-45a7-ace9-6708fe8f6504" = true ================================================ FILE: exercises/practice/dominoes/.meta/version ================================================ 2.1.0 ================================================ FILE: exercises/practice/dominoes/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/dominoes/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/dominoes/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/dominoes/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/dominoes/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/dominoes/src/main/kotlin/Dominoes.kt ================================================ class ChainNotFoundException(msg: String) : RuntimeException(msg) data class Domino(val left: Int, val right: Int) object Dominoes { fun formChain(inputDominoes: List): List { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/dominoes/src/test/kotlin/DominoesTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class DominoesTest { @Test fun `empty input = empty output`() = Dominoes.formChain().should { haveSize(0) } @Ignore @Test fun `singleton input = singleton output`() { val input = listOf(Domino(1, 1)) Dominoes.formChain(input).should { beValidDominoes(input) } } @Ignore @Test(ChainNotFoundException::class) fun `singleton can't be chained`() { Dominoes.formChain(Domino(1, 2)) } @Ignore @Test fun `three elements`() { val input = listOf(Domino(1, 2), Domino(3, 1), Domino(2, 3)) Dominoes.formChain(input).should { beValidDominoes(input) } } @Ignore @Test fun `can reverse dominoes`() { val input = listOf(Domino(1, 2), Domino(1, 3), Domino(2, 3)) Dominoes.formChain(input).should { beValidDominoes(input) } } @Ignore @Test(expected = ChainNotFoundException::class) fun `can't be chained`() { Dominoes.formChain(Domino(1, 2), Domino(4, 1), Domino(2, 3)) } @Ignore @Test(expected = ChainNotFoundException::class) fun `disconnected - simple`() { Dominoes.formChain(Domino(1, 1), Domino(2, 2)) } @Ignore @Test(expected = ChainNotFoundException::class) fun `disconnected - double loop`() { Dominoes.formChain(Domino(1, 2), Domino(2, 1), Domino(3, 4), Domino(4, 3)) } @Ignore @Test(expected = ChainNotFoundException::class) fun `disconnected - single isolated`() { Dominoes.formChain(Domino(1, 2), Domino(2, 3), Domino(3, 1), Domino(4, 4)) } @Ignore @Test fun `need backtrack`() { val input = listOf( Domino(1, 2), Domino(2, 3), Domino(3, 1), Domino(2, 4), Domino(4, 2)) Dominoes.formChain(input).should { beValidDominoes(input) } } @Ignore @Test fun `separate loops`() { val input = listOf( Domino(1, 2), Domino(2, 3), Domino(3, 1), Domino(1, 1), Domino(2, 2), Domino(3, 3)) Dominoes.formChain(input).should { beValidDominoes(input) } } @Ignore @Test fun `nine elements`() { val input = listOf( Domino(1, 2), Domino(5, 3), Domino(3, 1), Domino(1, 2), Domino(2, 4), Domino(1, 6), Domino(2, 3), Domino(3, 4), Domino(5, 6)) Dominoes.formChain(input).should { beValidDominoes(input) } } private fun List.should(what: DominoListAsserter.() -> Unit) = what(DominoListAsserter(this)) private class DominoListAsserter(private val outputDominoes: List) { fun haveSize(n: Int) = assertEquals(n, outputDominoes.size) fun beValidDominoes(inputDominoes: List) { haveSameDominoesAs(inputDominoes) haveMatchingEnds() haveConsecutiveDominoes() } private fun haveSameDominoesAs(inputDominoes: List) { val errorMessage = "The number of dominoes in the input list (${inputDominoes.size}) needs to match the number of dominoes in the output chain (${outputDominoes.size})" assertEquals(inputDominoes.size, outputDominoes.size, errorMessage) inputDominoes.forEach { domino -> val inputFrequency: Int = dominoFrequency(inputDominoes, domino) val outputFrequency: Int = dominoFrequency(outputDominoes, domino) val frequencyErrorMessage = "The frequency of domino (${domino.left}, ${domino.right}) in the input is ($inputFrequency), but ($outputFrequency) in the output." assertEquals(inputFrequency, outputFrequency, frequencyErrorMessage) } } private fun haveMatchingEnds() { val leftValueOfFirstDomino = outputDominoes.first().left val rightValueOfLastDomino = outputDominoes.last().right val errorMessage = "The left value of the first domino ($leftValueOfFirstDomino) needs to match the right value of the last domino ($rightValueOfLastDomino)." assertEquals(leftValueOfFirstDomino, rightValueOfLastDomino, errorMessage) } private fun haveConsecutiveDominoes() { (0 until outputDominoes.size - 1).forEach { i -> val rightValueOfIthDomino = outputDominoes[i].right val leftValueOfNextDomino = outputDominoes[i + 1].left val errorMessage = "The right value of domino number $i ($rightValueOfIthDomino) needs to match the left value of domino number ${i + 1} ($leftValueOfNextDomino)." assertEquals(outputDominoes[i].right, outputDominoes[i + 1].left, errorMessage) } } private fun dominoFrequency(list: List, d: Domino) = list.count { (it.left == d.left && it.right == d.right) || (it.left == d.right && it.right == d.left) } } } ================================================ FILE: exercises/practice/eliuds-eggs/.docs/instructions.md ================================================ # Instructions Your task is to count the number of 1 bits in the binary representation of a number. ## Restrictions Keep your hands off that bit-count functionality provided by your standard library! Solve this one yourself using other basic tools instead. ================================================ FILE: exercises/practice/eliuds-eggs/.docs/introduction.md ================================================ # Introduction Your friend Eliud inherited a farm from her grandma Tigist. Her granny was an inventor and had a tendency to build things in an overly complicated manner. The chicken coop has a digital display showing an encoded number representing the positions of all eggs that could be picked up. Eliud is asking you to write a program that shows the actual number of eggs in the coop. The position information encoding is calculated as follows: 1. Scan the potential egg-laying spots and mark down a `1` for an existing egg or a `0` for an empty spot. 2. Convert the number from binary to decimal. 3. Show the result on the display. ## Example 1 ![Seven individual nest boxes arranged in a row whose first, third, fourth and seventh nests each have a single egg.](https://assets.exercism.org/images/exercises/eliuds-eggs/example-1-coop.svg) ```text _ _ _ _ _ _ _ |E| |E|E| | |E| ``` ### Resulting Binary ![1011001](https://assets.exercism.org/images/exercises/eliuds-eggs/example-1-binary.svg) ```text _ _ _ _ _ _ _ |1|0|1|1|0|0|1| ``` ### Decimal number on the display 89 ### Actual eggs in the coop 4 ## Example 2 ![Seven individual nest boxes arranged in a row where only the fourth nest has an egg.](https://assets.exercism.org/images/exercises/eliuds-eggs/example-2-coop.svg) ```text _ _ _ _ _ _ _ | | | |E| | | | ``` ### Resulting Binary ![0001000](https://assets.exercism.org/images/exercises/eliuds-eggs/example-2-binary.svg) ```text _ _ _ _ _ _ _ |0|0|0|1|0|0|0| ``` ### Decimal number on the display 16 ### Actual eggs in the coop 1 ================================================ FILE: exercises/practice/eliuds-eggs/.meta/config.json ================================================ { "authors": [ "BNAndras" ], "files": { "solution": [ "src/main/kotlin/EliudsEggs.kt" ], "test": [ "src/test/kotlin/EliudsEggsTest.kt" ], "example": [ ".meta/src/reference/kotlin/EliudsEggs.kt" ] }, "blurb": "Help Eliud count the number of eggs in her chicken coop by counting the number of 1 bits in a binary representation.", "source": "Christian Willner, Eric Willigers", "source_url": "https://forum.exercism.org/t/new-exercise-suggestion-pop-count/7632/5" } ================================================ FILE: exercises/practice/eliuds-eggs/.meta/src/reference/kotlin/EliudsEggs.kt ================================================ object EliudsEggs { fun eggCount(number: Int): Int{ return number.countOneBits() } } ================================================ FILE: exercises/practice/eliuds-eggs/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [559e789d-07d1-4422-9004-3b699f83bca3] description = "0 eggs" [97223282-f71e-490c-92f0-b3ec9e275aba] description = "1 egg" [1f8fd18f-26e9-4144-9a0e-57cdfc4f4ff5] description = "4 eggs" [0c18be92-a498-4ef2-bcbb-28ac4b06cb81] description = "13 eggs" ================================================ FILE: exercises/practice/eliuds-eggs/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/eliuds-eggs/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/eliuds-eggs/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/eliuds-eggs/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/eliuds-eggs/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/eliuds-eggs/src/main/kotlin/EliudsEggs.kt ================================================ object EliudsEggs { fun eggCount(number: Int): Int{ TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/eliuds-eggs/src/test/kotlin/EliudsEggsTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class EliudsEggsTest { @Test fun `0 eggs`() = assertEquals(0, EliudsEggs.eggCount(0)) @Ignore @Test fun `1 egg`() = assertEquals(1, EliudsEggs.eggCount(16)) @Ignore @Test fun `4 eggs`() = assertEquals(4, EliudsEggs.eggCount(89)) @Ignore @Test fun `13 eggs`() = assertEquals(13, EliudsEggs.eggCount(2_000_000_000)) } ================================================ FILE: exercises/practice/etl/.docs/instructions.md ================================================ # Instructions Your task is to change the data format of letters and their point values in the game. Currently, letters are stored in groups based on their score, in a one-to-many mapping. - 1 point: "A", "E", "I", "O", "U", "L", "N", "R", "S", "T", - 2 points: "D", "G", - 3 points: "B", "C", "M", "P", - 4 points: "F", "H", "V", "W", "Y", - 5 points: "K", - 8 points: "J", "X", - 10 points: "Q", "Z", This needs to be changed to store each individual letter with its score in a one-to-one mapping. - "a" is worth 1 point. - "b" is worth 3 points. - "c" is worth 3 points. - "d" is worth 2 points. - etc. As part of this change, the team has also decided to change the letters to be lower-case rather than upper-case. ~~~~exercism/note If you want to look at how the data was previously structured and how it needs to change, take a look at the examples in the test suite. ~~~~ ================================================ FILE: exercises/practice/etl/.docs/introduction.md ================================================ # Introduction You work for a company that makes an online multiplayer game called Lexiconia. To play the game, each player is given 13 letters, which they must rearrange to create words. Different letters have different point values, since it's easier to create words with some letters than others. The game was originally launched in English, but it is very popular, and now the company wants to expand to other languages as well. Different languages need to support different point values for letters. The point values are determined by how often letters are used, compared to other letters in that language. For example, the letter 'C' is quite common in English, and is only worth 3 points. But in Norwegian it's a very rare letter, and is worth 10 points. To make it easier to add new languages, your team needs to change the way letters and their point values are stored in the game. ================================================ FILE: exercises/practice/etl/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ETL.kt" ], "test": [ "src/test/kotlin/ETLTest.kt" ], "example": [ ".meta/src/reference/kotlin/ETL.kt" ] }, "blurb": "Change the data format for scoring a game to more easily add other languages.", "source": "Based on an exercise by the JumpstartLab team for students at The Turing School of Software and Design.", "source_url": "https://turing.edu" } ================================================ FILE: exercises/practice/etl/.meta/src/reference/kotlin/ETL.kt ================================================ object ETL { fun transform(old: Map>): Map { return old.flatMap { mapEntry -> mapEntry.value.map { word -> Pair(word.lowercaseChar(), mapEntry.key) } }.toMap() } } ================================================ FILE: exercises/practice/etl/.meta/tests.toml ================================================ [canonical-tests] # single letter "78a7a9f9-4490-4a47-8ee9-5a38bb47d28f" = true # single score with multiple letters "60dbd000-451d-44c7-bdbb-97c73ac1f497" = true # multiple scores with multiple letters "f5c5de0c-301f-4fdd-a0e5-df97d4214f54" = true # multiple scores with differing numbers of letters "5db8ea89-ecb4-4dcd-902f-2b418cc87b9d" = true ================================================ FILE: exercises/practice/etl/.meta/version ================================================ 2.0.1 ================================================ FILE: exercises/practice/etl/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/etl/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/etl/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/etl/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/etl/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/etl/src/main/kotlin/ETL.kt ================================================ object ETL { fun transform(source: Map>): Map { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/etl/src/test/kotlin/ETLTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class ETLTest { @Test fun `single letter`() = assertTransformedEquals( mapOf( 1 to listOf('A')), mapOf( 'a' to 1)) @Ignore @Test fun `single score with multiple letters`() = assertTransformedEquals( mapOf( 1 to listOf('A', 'E', 'I', 'O', 'U')), mapOf( 'a' to 1, 'e' to 1, 'i' to 1, 'o' to 1, 'u' to 1)) @Ignore @Test fun `multiple scores with multiple letters`() = assertTransformedEquals( mapOf( 1 to listOf('A', 'E'), 2 to listOf('D', 'G')), mapOf( 'a' to 1, 'd' to 2, 'e' to 1, 'g' to 2)) @Ignore @Test fun `multiple scores with differing numbers of letters`() = assertTransformedEquals( mapOf( 1 to listOf('A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T'), 2 to listOf('D', 'G'), 3 to listOf('B', 'C', 'M', 'P'), 4 to listOf('F', 'H', 'V', 'W', 'Y'), 5 to listOf('K'), 8 to listOf('J', 'X'), 10 to listOf('Q', 'Z')), mapOf( 'a' to 1, 'b' to 3, 'c' to 3, 'd' to 2, 'e' to 1, 'f' to 4, 'g' to 2, 'h' to 4, 'i' to 1, 'j' to 8, 'k' to 5, 'l' to 1, 'm' to 3, 'n' to 1, 'o' to 1, 'p' to 3, 'q' to 10, 'r' to 1, 's' to 1, 't' to 1, 'u' to 1, 'v' to 4, 'w' to 4, 'x' to 8, 'y' to 4, 'z' to 10)) } private fun assertTransformedEquals(input: Map>, expectation: Map) = assertEquals(expectation, ETL.transform(input)) ================================================ FILE: exercises/practice/flatten-array/.docs/instructions.md ================================================ # Instructions Take a nested array of any depth and return a fully flattened array. Note that some language tracks may include null-like values in the input array, and the way these values are represented varies by track. Such values should be excluded from the flattened array. Additionally, the input may be of a different data type and contain different types, depending on the track. Check the test suite for details. ## Example input: `[1, [2, 6, null], [[null, [4]], 5]]` output: `[1, 2, 6, 4, 5]` ================================================ FILE: exercises/practice/flatten-array/.docs/introduction.md ================================================ # Introduction A shipment of emergency supplies has arrived, but there's a problem. To protect from damage, the items — flashlights, first-aid kits, blankets — are packed inside boxes, and some of those boxes are nested several layers deep inside other boxes! To be prepared for an emergency, everything must be easily accessible in one box. Can you unpack all the supplies and place them into a single box, so they're ready when needed most? ================================================ FILE: exercises/practice/flatten-array/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Flattener.kt" ], "test": [ "src/test/kotlin/FlattenerTest.kt" ], "example": [ ".meta/src/reference/kotlin/Flattener.kt" ] }, "blurb": "Take a nested list and return a single list with all values except nil/null.", "source": "Interview Question", "source_url": "https://reference.wolfram.com/language/ref/Flatten.html" } ================================================ FILE: exercises/practice/flatten-array/.meta/src/reference/kotlin/Flattener.kt ================================================ object Flattener { fun flatten(unflattened: Collection): List { return unflattened.filterNotNull().fold(mutableListOf()) { accum, element -> accum.addFlattened(element); accum } } fun MutableCollection.addFlattened(item: Any) = if (item is Collection<*>) this.addAll(flatten(item)) else this.add(item) } ================================================ FILE: exercises/practice/flatten-array/.meta/tests.toml ================================================ [canonical-tests] # no nesting "d268b919-963c-442d-9f07-82b93f1b518c" = true # flattens array with just integers present "c84440cc-bb3a-48a6-862c-94cf23f2815d" = true # 5 level nesting "d3d99d39-6be5-44f5-a31d-6037d92ba34f" = true # 6 level nesting "d572bdba-c127-43ed-bdcd-6222ac83d9f7" = true # 6 level nest list with null values "ef1d4790-1b1e-4939-a179-51ace0829dbd" = true # all values in nested list are null "85721643-705a-4150-93ab-7ae398e2942d" = true ================================================ FILE: exercises/practice/flatten-array/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/flatten-array/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/flatten-array/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/flatten-array/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/flatten-array/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/flatten-array/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/flatten-array/src/main/kotlin/Flattener.kt ================================================ object Flattener { fun flatten(source: Collection): List { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/flatten-array/src/test/kotlin/FlattenerTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class FlattenerTest { @Test fun flatListIsUnchanged() { val flatList = listOf(0, 1, 2) assertEquals(listOf(0, 1, 2), Flattener.flatten(flatList)) } @Ignore @Test fun flattens2LevelNestedList() { val nestedList = listOf(1, listOf(2, 3, 4, 5, 6, 7), 8) assertEquals(listOf(1, 2, 3, 4, 5, 6, 7, 8), Flattener.flatten(nestedList)) } @Ignore @Test fun flattens5LevelNestedList() { val nestedList = listOf(0, 2, listOf(listOf(2, 3), 8, 100, 4, listOf(listOf(listOf(50))), -2)) assertEquals(listOf(0, 2, 2, 3, 8, 100, 4, 50, -2), Flattener.flatten(nestedList)) } @Ignore @Test fun flattens6LevelNestedList() { val nestedList = listOf(1, listOf(2, listOf(listOf(3)), listOf(4, listOf(listOf(5))), 6, 7), 8) assertEquals(listOf(1, 2, 3, 4, 5, 6, 7, 8), Flattener.flatten(nestedList)) } @Ignore @Test fun flattens6LevelNestedListWithNulls() { val nestedList = listOf(0, 2, listOf(listOf(2, 3), 8, listOf(listOf(100)), null, listOf(listOf(null))), -2) assertEquals(listOf(0, 2, 2, 3, 8, 100, -2), Flattener.flatten(nestedList)) } @Ignore @Test fun allNullNestedListReturnsEmptyList() { val nestedList = listOf(null, listOf(listOf(listOf(null))), null, null, listOf(listOf(null, null), null), null) assertEquals(emptyList(), Flattener.flatten(nestedList)) } @Ignore @Test fun flattensHeterogenousList() { val nestedList = listOf(0, 2.1, listOf(listOf(true, "flatten"), 'a', listOf(listOf(100)), null, listOf(listOf(null))), -2) assertEquals(listOf(0, 2.1, true, "flatten", 'a', 100, -2), Flattener.flatten(nestedList)) } } ================================================ FILE: exercises/practice/flower-field/.docs/instructions.md ================================================ # Instructions Your task is to add flower counts to empty squares in a completed Flower Field garden. The garden itself is a rectangle board composed of squares that are either empty (`' '`) or a flower (`'*'`). For each empty square, count the number of flowers adjacent to it (horizontally, vertically, diagonally). If the empty square has no adjacent flowers, leave it empty. Otherwise replace it with the count of adjacent flowers. For example, you may receive a 5 x 4 board like this (empty spaces are represented here with the '·' character for display on screen): ```text ·*·*· ··*·· ··*·· ····· ``` Which your code should transform into this: ```text 1*3*1 13*31 ·2*2· ·111· ``` ================================================ FILE: exercises/practice/flower-field/.docs/introduction.md ================================================ # Introduction [Flower Field][history] is a compassionate reimagining of the popular game Minesweeper. The object of the game is to find all the flowers in the garden using numeric hints that indicate how many flowers are directly adjacent (horizontally, vertically, diagonally) to a square. "Flower Field" shipped in regional versions of Microsoft Windows in Italy, Germany, South Korea, Japan and Taiwan. [history]: https://web.archive.org/web/20020409051321fw_/http://rcm.usr.dsi.unimi.it/rcmweb/fnm/ ================================================ FILE: exercises/practice/flower-field/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "BNAndras", "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/FlowerField.kt" ], "test": [ "src/test/kotlin/FlowerFieldTest.kt" ], "example": [ ".meta/src/reference/kotlin/FlowerField.kt" ] }, "blurb": "Mark all the flowers in a garden." } ================================================ FILE: exercises/practice/flower-field/.meta/src/reference/kotlin/FlowerField.kt ================================================ import kotlin.math.max import kotlin.math.min private const val FLOWER_CHAR = '*' private const val SPACE_CHAR = ' ' data class FlowerFieldBoard(val flowerLocations: List) { private val numberOfRows by lazy { flowerLocations.size } private val numberOfColumns by lazy { if (flowerLocations.isEmpty()) 0 else flowerLocations[0].length } fun withNumbers() = (0 until numberOfRows).map { getRowWithNumbers(it) } private fun getRowWithNumbers(rowNumber: Int) = (0 until numberOfColumns) .map { columnNumber -> getCellNumber(rowNumber, columnNumber) } .joinToString("") private fun getCellNumber(rowNumber: Int, columnNumber: Int): Char { // If (rowNumber, columnNumber) is a flower, we're done. if (flowerLocations[rowNumber][columnNumber] == FLOWER_CHAR) { return FLOWER_CHAR } val flowerCount = computeFlowerCountAround(rowNumber, columnNumber) // If computed count is positive, add it to the annotated row. Otherwise, add a blank space. return if (flowerCount > 0) Character.forDigit(flowerCount, 10) else SPACE_CHAR } private fun computeFlowerCountAround(rowNumber: Int, columnNumber: Int): Int { var result = 0 // Compute row and column ranges to inspect (respecting board edges). val minRowToInspect = max(rowNumber - 1, 0) val maxRowToInspect = min(rowNumber + 1, numberOfRows - 1) val minColToInspect = max(columnNumber - 1, 0) val maxColToInspect = min(columnNumber + 1, numberOfColumns - 1) // Count flowerss in the cells surrounding (row, col). for (rowToInspect in minRowToInspect..maxRowToInspect) { for (colToInspect in minColToInspect..maxColToInspect) { if (flowerLocations[rowToInspect][colToInspect] == FLOWER_CHAR) { result += 1 } } } return result } } ================================================ FILE: exercises/practice/flower-field/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [237ff487-467a-47e1-9b01-8a891844f86c] description = "no rows" [4b4134ec-e20f-439c-a295-664c38950ba1] description = "no columns" [d774d054-bbad-4867-88ae-069cbd1c4f92] description = "no flowers" [225176a0-725e-43cd-aa13-9dced501f16e] description = "garden full of flowers" [3f345495-f1a5-4132-8411-74bd7ca08c49] description = "flower surrounded by spaces" [6cb04070-4199-4ef7-a6fa-92f68c660fca] description = "space surrounded by flowers" [272d2306-9f62-44fe-8ab5-6b0f43a26338] description = "horizontal line" [c6f0a4b2-58d0-4bf6-ad8d-ccf4144f1f8e] description = "horizontal line, flowers at edges" [a54e84b7-3b25-44a8-b8cf-1753c8bb4cf5] description = "vertical line" [b40f42f5-dec5-4abc-b167-3f08195189c1] description = "vertical line, flowers at edges" [58674965-7b42-4818-b930-0215062d543c] description = "cross" [dd9d4ca8-9e68-4f78-a677-a2a70fd7a7b8] description = "large garden" ================================================ FILE: exercises/practice/flower-field/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/flower-field/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/flower-field/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/flower-field/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/flower-field/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/flower-field/src/main/kotlin/FlowerField.kt ================================================ data class FlowerFieldBoard(val todo: Nothing) { // TODO: Implement proper constructor fun withNumbers(): List { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/flower-field/src/test/kotlin/FlowerFieldTest.kt ================================================ import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException import kotlin.test.assertEquals class FlowerFieldBoardTest { /* * See https://github.com/junit-team/junit4/wiki/Rules for information on JUnit Rules in general and * ExpectedExceptions in particular. */ @Rule @JvmField var expectedException: ExpectedException = ExpectedException.none() @Test fun testInputBoardWithNoRowsAndNoColumns() { val inputBoard = emptyList() val expectedNumberedBoard = emptyList() val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithOneRowAndNoColumns() { val inputBoard = listOf("") val expectedNumberedBoard = listOf("") val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithNoFlowers() { val inputBoard = listOf( " ", " ", " " ) val expectedNumberedBoard = listOf( " ", " ", " " ) val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithOnlyFlowers() { val inputBoard = listOf( "***", "***", "***" ) val expectedNumberedBoard = listOf( "***", "***", "***" ) val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleFlowerAtCenter() { val inputBoard = listOf( " ", " * ", " " ) val expectedNumberedBoard = listOf( "111", "1*1", "111" ) val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithFlowersAroundPerimeter() { val inputBoard = listOf( "***", "* *", "***" ) val expectedNumberedBoard = listOf( "***", "*8*", "***" ) val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleRowAndTwoFlowers() { val inputBoard = listOf(" * * ") val expectedNumberedBoard = listOf("1*2*1") val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleRowAndTwoFlowersAtEdges() { val inputBoard = listOf("* *") val expectedNumberedBoard = listOf("*1 1*") val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleColumnAndTwoFlowers() { val inputBoard = listOf( " ", "*", " ", "*", " " ) val expectedNumberedBoard = listOf( "1", "*", "2", "*", "1" ) val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleColumnAndTwoFlowersAtEdges() { val inputBoard = listOf( "*", " ", " ", " ", "*" ) val expectedNumberedBoard = listOf( "*", "1", " ", "1", "*" ) val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithFlowersInCross() { val inputBoard = listOf( " * ", " * ", "*****", " * ", " * " ) val expectedNumberedBoard = listOf( " 2*2 ", "25*52", "*****", "25*52", " 2*2 " ) val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testLargeInputBoard() { val inputBoard = listOf( " * * ", " * ", " * ", " * *", " * * ", " " ) val expectedNumberedBoard = listOf( "1*22*1", "12*322", " 123*2", "112*4*", "1*22*2", "111111" ) val actualNumberedBoard = FlowerFieldBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } } ================================================ FILE: exercises/practice/forth/.docs/instructions.md ================================================ # Instructions Implement an evaluator for a very simple subset of Forth. [Forth][forth] is a stack-based programming language. Implement a very basic evaluator for a small subset of Forth. Your evaluator has to support the following words: - `+`, `-`, `*`, `/` (integer arithmetic) - `DUP`, `DROP`, `SWAP`, `OVER` (stack manipulation) Your evaluator also has to support defining new words using the customary syntax: `: word-name definition ;`. To keep things simple the only data type you need to support is signed integers of at least 16 bits size. You should use the following rules for the syntax: a number is a sequence of one or more (ASCII) digits, a word is a sequence of one or more letters, digits, symbols or punctuation that is not a number. (Forth probably uses slightly different rules, but this is close enough.) Words are case-insensitive. [forth]: https://en.wikipedia.org/wiki/Forth_%28programming_language%29 ================================================ FILE: exercises/practice/forth/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "eparovyshnaya", "lathspell", "lihofm", "luoken", "mdowds", "mikegehard", "sjwarner-bp", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Forth.kt" ], "test": [ "src/test/kotlin/ForthTest.kt" ], "example": [ ".meta/src/reference/kotlin/Forth.kt" ] }, "blurb": "Implement an evaluator for a very simple subset of Forth." } ================================================ FILE: exercises/practice/forth/.meta/src/reference/kotlin/Forth.kt ================================================ import java.util.* class Forth { companion object { private val NUMBER_PATTERN = Regex("""^-?\d+$""") } private val stack: Deque = ArrayDeque() private val customOps: MutableMap = mutableMapOf() private val ops = mutableMapOf( "+" to { require(stack.isNotEmpty()) { "empty stack" } require(stack.size >= 2) { "only one value on the stack" } stack.push(stack.pop() + stack.pop()) }, "-" to { require(stack.isNotEmpty()) { "empty stack" } require(stack.size >= 2) { "only one value on the stack" } val tmp = stack.pop() stack.push(stack.pop() - tmp) }, "*" to { require(stack.isNotEmpty()) { "empty stack" } require(stack.size >= 2) { "only one value on the stack" } stack.push(stack.pop() * stack.pop()) }, "/" to { require(stack.isNotEmpty()) { "empty stack" } require(stack.size >= 2) { "only one value on the stack" } val tmp = stack.pop() require(tmp != 0) { "divide by zero" } stack.push(stack.pop() / tmp) }, "DUP" to { require(stack.isNotEmpty()) { "empty stack" } stack.push(stack.first) }, "DROP" to { require(stack.isNotEmpty()) { "empty stack" } stack.pop() }, "SWAP" to { require(stack.isNotEmpty()) { "empty stack" } require(stack.size >= 2) { "only one value on the stack" } val a = stack.pop() val b = stack.pop() stack.push(a) stack.push(b) }, "OVER" to { require(stack.isNotEmpty()) { "empty stack" } require(stack.size >= 2) { "only one value on the stack" } stack.push(stack.elementAt(1)) } ); fun evaluate(vararg lines: String): List { lines.forEach { line -> evaluateLine(line.uppercase()) } return stack.reversed() } private fun evaluateLine(line: String) { val tokens = line.split(" ") if (tokens.first() == ":") { val op = tokens[1] val expression = tokens.subList(2, tokens.lastIndex) require(!op.matches(NUMBER_PATTERN)) { "illegal operation" } customOps[op] = expression.joinToString(" ") { customOps.getOrDefault(it, it) } return } tokens.forEach { token -> when { token.matches(NUMBER_PATTERN) -> stack.push(token.toInt()) token in customOps.keys -> evaluateLine(customOps[token]!!) token in ops.keys -> ops[token]!!() else -> throw IllegalArgumentException("undefined operation") } } } } ================================================ FILE: exercises/practice/forth/.meta/tests.toml ================================================ [canonical-tests] # numbers just get pushed onto the stack "9962203f-f00a-4a85-b404-8a8ecbcec09d" = true # can add two numbers "9e69588e-a3d8-41a3-a371-ea02206c1e6e" = true # errors if there is nothing on the stack "52336dd3-30da-4e5c-8523-bdf9a3427657" = true # errors if there is only one value on the stack "06efb9a4-817a-435e-b509-06166993c1b8" = true # can subtract two numbers "09687c99-7bbc-44af-8526-e402f997ccbf" = true # errors if there is nothing on the stack "5d63eee2-1f7d-4538-b475-e27682ab8032" = true # errors if there is only one value on the stack "b3cee1b2-9159-418a-b00d-a1bb3765c23b" = true # can multiply two numbers "5df0ceb5-922e-401f-974d-8287427dbf21" = true # errors if there is nothing on the stack "9e004339-15ac-4063-8ec1-5720f4e75046" = true # errors if there is only one value on the stack "8ba4b432-9f94-41e0-8fae-3b3712bd51b3" = true # can divide two numbers "e74c2204-b057-4cff-9aa9-31c7c97a93f5" = true # performs integer division "54f6711c-4b14-4bb0-98ad-d974a22c4620" = true # errors if dividing by zero "a5df3219-29b4-4d2f-b427-81f82f42a3f1" = true # errors if there is nothing on the stack "1d5bb6b3-6749-4e02-8a79-b5d4d334cb8a" = true # errors if there is only one value on the stack "d5547f43-c2ff-4d5c-9cb0-2a4f6684c20d" = true # addition and subtraction "ee28d729-6692-4a30-b9be-0d830c52a68c" = true # multiplication and division "40b197da-fa4b-4aca-a50b-f000d19422c1" = true # copies a value on the stack "c5758235-6eef-4bf6-ab62-c878e50b9957" = true # copies the top value on the stack "f6889006-5a40-41e7-beb3-43b09e5a22f4" = true # errors if there is nothing on the stack "40b7569c-8401-4bd4-a30d-9adf70d11bc4" = true # removes the top value on the stack if it is the only one "1971da68-1df2-4569-927a-72bf5bb7263c" = true # removes the top value on the stack if it is not the only one "8929d9f2-4a78-4e0f-90ad-be1a0f313fd9" = true # errors if there is nothing on the stack "6dd31873-6dd7-4cb8-9e90-7daa33ba045c" = true # swaps the top two values on the stack if they are the only ones "3ee68e62-f98a-4cce-9e6c-8aae6c65a4e3" = true # swaps the top two values on the stack if they are not the only ones "8ce869d5-a503-44e4-ab55-1da36816ff1c" = true # errors if there is nothing on the stack "74ba5b2a-b028-4759-9176-c5c0e7b2b154" = true # errors if there is only one value on the stack "dd52e154-5d0d-4a5c-9e5d-73eb36052bc8" = true # copies the second element if there are only two "a2654074-ba68-4f93-b014-6b12693a8b50" = true # copies the second element if there are more than two "c5b51097-741a-4da7-8736-5c93fa856339" = true # errors if there is nothing on the stack "6e1703a6-5963-4a03-abba-02e77e3181fd" = true # errors if there is only one value on the stack "ee574dc4-ef71-46f6-8c6a-b4af3a10c45f" = true # can consist of built-in words "ed45cbbf-4dbf-4901-825b-54b20dbee53b" = true # execute in the right order "2726ea44-73e4-436b-bc2b-5ff0c6aa014b" = true # can override other user-defined words "9e53c2d0-b8ef-4ad8-b2c9-a559b421eb33" = true # can override built-in words "669db3f3-5bd6-4be0-83d1-618cd6e4984b" = true # can override built-in operators "588de2f0-c56e-4c68-be0b-0bb1e603c500" = true # can use different words with the same name "ac12aaaf-26c6-4a10-8b3c-1c958fa2914c" = true # can define word that uses word with the same name "53f82ef0-2750-4ccb-ac04-5d8c1aefabb1" = true # cannot redefine numbers "35958cee-a976-4a0f-9378-f678518fa322" = true # errors if executing a non-existent word "5180f261-89dd-491e-b230-62737e09806f" = true # DUP is case-insensitive "7b83bb2e-b0e8-461f-ad3b-96ee2e111ed6" = true # DROP is case-insensitive "339ed30b-f5b4-47ff-ab1c-67591a9cd336" = true # SWAP is case-insensitive "ee1af31e-1355-4b1b-bb95-f9d0b2961b87" = true # OVER is case-insensitive "acdc3a49-14c8-4cc2-945d-11edee6408fa" = true # user-defined words are case-insensitive "5934454f-a24f-4efc-9fdd-5794e5f0c23c" = true # definitions are case-insensitive "037d4299-195f-4be7-a46d-f07ca6280a06" = true ================================================ FILE: exercises/practice/forth/.meta/version ================================================ 1.7.1 ================================================ FILE: exercises/practice/forth/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation(kotlin("test")) } tasks.withType { useJUnitPlatform() testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/forth/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/forth/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/forth/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/forth/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/forth/src/main/kotlin/Forth.kt ================================================ class Forth { fun evaluate(vararg line: String): List { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/forth/src/test/kotlin/ForthTest.kt ================================================ import org.junit.jupiter.api.Nested import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFails @Nested class ForthTest { @Nested inner class ParsingAndNumbersTest { @Test fun `numbers just get pushed onto the stack`() = assertEquals(listOf(1, 2, 3, 4, 5), Forth().evaluate("1 2 3 4 5")) } @Nested inner class Addition { @Ignore @Test fun `can add two numbers`() = assertEquals(listOf(3), Forth().evaluate("1 2 +")) @Ignore @Test fun `errors if there is nothing on the stack`() { val ex = assertFails { Forth().evaluate("+") } assertEquals("empty stack", ex.message) } @Ignore @Test fun `errors if there is only one value on the stack`() { val ex = assertFails { Forth().evaluate("1 +") } assertEquals("only one value on the stack", ex.message) } } @Nested inner class Subtraction { @Ignore @Test fun `can subtract two numbers`() = assertEquals(listOf(-1), Forth().evaluate("3 4 -")) @Ignore @Test fun `errors if there is nothing on the stack`() { val ex = assertFails { Forth().evaluate("-") } assertEquals("empty stack", ex.message) } @Ignore @Test fun `errors if there is only one value on the stack`() { val ex = assertFails { Forth().evaluate("1 -") } assertEquals("only one value on the stack", ex.message) } } @Nested inner class Multiplication { @Ignore @Test fun `can multiply two numbers`() = assertEquals(listOf(8), Forth().evaluate("2 4 *")) @Ignore @Test fun `errors if there is nothing on the stack`() { val ex = assertFails { Forth().evaluate("*") } assertEquals("empty stack", ex.message) } @Ignore @Test fun `errors if there is only one value on the stack`() { val ex = assertFails { Forth().evaluate("1 *") } assertEquals("only one value on the stack", ex.message) } } @Nested inner class Division { @Ignore @Test fun `can divide two numbers`() = assertEquals(listOf(4), Forth().evaluate("12 3 /")) @Ignore @Test fun `performs integer division`() = assertEquals(listOf(2), Forth().evaluate("8 3 /")) @Ignore @Test fun `errors if dividing by zero`() { val ex = assertFails { Forth().evaluate("4 0 /") } assertEquals("divide by zero", ex.message) } @Ignore @Test fun `errors if there is nothing on the stack`() { val ex = assertFails { Forth().evaluate("/") } assertEquals("empty stack", ex.message) } @Ignore @Test fun `errors if there is only one value on the stack`() { val ex = assertFails { Forth().evaluate("1 /") } assertEquals("only one value on the stack", ex.message) } } @Nested inner class CombinedArithmetic { @Ignore @Test fun `addition and subtraction`() = assertEquals(listOf(-1), Forth().evaluate("1 2 + 4 -")) @Ignore @Test fun `multiplication and division`() = assertEquals(listOf(2), Forth().evaluate("2 4 * 3 /")) } @Nested inner class Dup { @Ignore @Test fun `copies a value on the stack`() = assertEquals(listOf(1, 1), Forth().evaluate("1 dup")) @Ignore @Test fun `copies the top value on the stack`() = assertEquals(listOf(1, 2, 2), Forth().evaluate("1 2 dup")) @Ignore @Test fun `errors if there is nothing on the stack`() { val ex = assertFails { Forth().evaluate("dup") } assertEquals("empty stack", ex.message) } } @Nested inner class Drop { @Ignore @Test fun `removes the top value on the stack if it is the only one`() = assertEquals(emptyList(), Forth().evaluate("1 drop")) @Ignore @Test fun `removes the top value on the stack if it is not the only one`() = assertEquals(listOf(1), Forth().evaluate("1 2 drop")) @Ignore @Test fun `errors if there is nothing on the stack`() { val ex = assertFails { Forth().evaluate("drop") } assertEquals("empty stack", ex.message) } } @Nested inner class Swap { @Ignore @Test fun `swaps the top two values on the stack if they are the only ones`() = assertEquals(listOf(2, 1), Forth().evaluate("1 2 swap")) @Ignore @Test fun `swaps the top two values on the stack if they are not the only ones`() = assertEquals(listOf(1, 3, 2), Forth().evaluate("1 2 3 swap")) @Ignore @Test fun `errors if there is nothing on the stack`() { val ex = assertFails { Forth().evaluate("swap") } assertEquals("empty stack", ex.message) } @Ignore @Test fun `errors if there is only one value on the stack`() { val ex = assertFails { Forth().evaluate("1 swap") } assertEquals("only one value on the stack", ex.message) } } @Nested inner class Over { @Ignore @Test fun `copies the second element if there are only two`() = assertEquals(listOf(1, 2, 1), Forth().evaluate("1 2 over")) @Ignore @Test fun `copies the second element if there are more than two`() = assertEquals(listOf(1, 2, 3, 2), Forth().evaluate("1 2 3 over")) @Ignore @Test fun `errors if there is nothing on the stack`() { val ex = assertFails { Forth().evaluate("over") } assertEquals("empty stack", ex.message) } @Ignore @Test fun `errors if there is only one value on the stack`() { val ex = assertFails { Forth().evaluate("1 over") } assertEquals("only one value on the stack", ex.message) } } @Nested inner class UserDefinedWords { @Ignore @Test fun `can consist of built-in words`() = assertEquals( listOf(1, 1, 1), Forth().evaluate( ": dup-twice dup dup ;", "1 dup-twice", ) ) @Ignore @Test fun `execute in the right order`() = assertEquals( listOf(1, 2, 3), Forth().evaluate( ": countup 1 2 3 ;", "countup", ) ) @Ignore @Test fun `can override other user-defined words`() = assertEquals( listOf(1, 1, 1), Forth().evaluate( ": foo dup ;", ": foo dup dup ;", "1 foo", ) ) @Ignore @Test fun `can override built-in words`() = assertEquals( listOf(1, 1), Forth().evaluate( ": swap dup ;", "1 swap", ) ) @Ignore @Test fun `can override built-in operators`() = assertEquals( listOf(12), Forth().evaluate( ": + * ;", "3 4 +", ) ) @Ignore @Test fun `can use different words with the same name`() = assertEquals( listOf(5, 6), Forth().evaluate( ": foo 5 ;", ": bar foo ;", ": foo 6 ;", "bar foo", ) ) @Ignore @Test fun `can define word that uses word with the same name`() = assertEquals( listOf(11), Forth().evaluate( ": foo 10 ;", ": foo foo 1 + ;", "foo", ) ) @Ignore @Test fun `cannot redefine numbers`() { val ex = assertFails { Forth().evaluate(": 1 2 ;") } assertEquals("illegal operation", ex.message) } @Ignore @Test fun `errors if executing a non-existent word`() { val ex = assertFails { Forth().evaluate("foo") } assertEquals("undefined operation", ex.message) } } @Nested inner class CaseInsensitivity { @Ignore @Test fun `DUP is case-insensitive`() = assertEquals(listOf(1, 1, 1, 1), Forth().evaluate("1 DUP Dup dup")) @Ignore @Test fun `DROP is case-insensitive`() = assertEquals(listOf(1), Forth().evaluate("1 2 3 4 DROP Drop drop")) @Ignore @Test fun `SWAP is case-insensitive`() = assertEquals(listOf(2, 3, 4, 1), Forth().evaluate("1 2 SWAP 3 Swap 4 swap")) @Ignore @Test fun `OVER is case-insensitive`() = assertEquals(listOf(1, 2, 1, 2, 1), Forth().evaluate("1 2 OVER Over over")) @Ignore @Test fun `user-defined words are case-insensitive`() = assertEquals( listOf(1, 1, 1, 1), Forth().evaluate(": foo dup ;", "1 FOO Foo foo") ) @Ignore @Test fun `definitions are case-insensitive`() = assertEquals( listOf(1, 1, 1, 1), Forth().evaluate( ": SWAP DUP Dup dup ;", "1 swap", ) ) } } ================================================ FILE: exercises/practice/gigasecond/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "54bff868-f84e-481e-ae00-bed8e960445e", "slug": "secondary-constructor-atstartofday", "title": "Secondary constructor with atStartOfDay", "blurb": "Use a secondary constructor with atStartOfDay to return the answer.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/gigasecond/.approaches/introduction.md ================================================ # Introduction There are several ways to solve Gigasecond. One approach is to use a [secondary constructor][constructors] with the [`atStartOfDay`][atstartofday] method of the [`LocalDate`][localdate] class. ## Approach: Secondary constructor with `atStartOfDay` ```kotlin import java.time.LocalDate import java.time.LocalDateTime class Gigasecond(baseDatetime: LocalDateTime) { private val gigaseconds: Long = 1_000_000_000 val date: LocalDateTime = baseDatetime.plusSeconds(gigaseconds) constructor(baseDate: LocalDate) : this(baseDate.atStartOfDay()) } ``` For more information, check the [Secondary constructor with atStartOfDay approach][approach-secondary-constructor-atstartofday]. [approach-secondary-constructor-atstartofday]: https://exercism.org/tracks/kotlin/exercises/gigasecond/approaches/secondary-constructor-atstartofday [constructors]: https://www.geeksforgeeks.org/kotlin-constructor/ [atstartofday]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#atStartOfDay-- [localdate]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html ================================================ FILE: exercises/practice/gigasecond/.approaches/secondary-constructor-atstartofday/content.md ================================================ # Secondary constructor with `atStartOfDay` ```kotlin import java.time.LocalDate import java.time.LocalDateTime class Gigasecond(baseDatetime: LocalDateTime) { private val gigaseconds: Long = 1_000_000_000 val date: LocalDateTime = baseDatetime.plusSeconds(gigaseconds) constructor(baseDate: LocalDate) : this(baseDate.atStartOfDay()) } ``` This approach starts by importng from libraries for what is needed. The `Gigasecond` class is defined with a [primary constructor][constructors] that takes a `LocalDateTime`. A [`private`][visibility] [`val`][variables] is defined to hold the value for one billion seconds. A `val` with a meaningful name is used instead of using the `1000000000` value as a [magic number][magic-number]. Note that [digit separators][digit-separators] (`_`) can make long numbers more readable. Another `val` is defined that uses the [`plusSeconds`][plusseconds] method to add a billion seconds to the value passed into the primary constructor. The `constructor` keyword is used to define a secondary constructor that takes a `LocalDate`. It uses the `this` keyword to call another constructor (in this case, the primary constructor.) The [`atStartOfDay`][atstartofday] method is used to convert the `LocalDate` to the `LocalDateTime` type accepted by the primary constructor. Calling one constructor from another is referrred to as "constructor chaining". [constructors]: https://www.geeksforgeeks.org/kotlin-constructor/ [visibility]: https://kotlinlang.org/docs/visibility-modifiers.html [variables]: https://kotlinlang.org/docs/basic-syntax.html#variables [magic-number]: https://en.wikipedia.org/wiki/Magic_number_(programming) [digit-separators]: https://docs.oracle.com/javase/7/docs/technotes/guides/language/underscores-literals.html [plusseconds]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#plusSeconds-long- [atstartofday]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#atStartOfDay-- [localdate]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html ================================================ FILE: exercises/practice/gigasecond/.approaches/secondary-constructor-atstartofday/snippet.txt ================================================ class Gigasecond(baseDatetime: LocalDateTime) { private val gigaseconds: Long = 1_000_000_000 val date: LocalDateTime = baseDatetime.plusSeconds(gigaseconds) constructor(baseDate: LocalDate) : this(baseDate.atStartOfDay()) } ================================================ FILE: exercises/practice/gigasecond/.docs/instructions.md ================================================ # Instructions Your task is to determine the date and time one gigasecond after a certain date. A gigasecond is one thousand million seconds. That is a one with nine zeros after it. If you were born on _January 24th, 2015 at 22:00 (10:00:00pm)_, then you would be a gigasecond old on _October 2nd, 2046 at 23:46:40 (11:46:40pm)_. ================================================ FILE: exercises/practice/gigasecond/.docs/introduction.md ================================================ # Introduction The way we measure time is kind of messy. We have 60 seconds in a minute, and 60 minutes in an hour. This comes from ancient Babylon, where they used 60 as the basis for their number system. We have 24 hours in a day, 7 days in a week, and how many days in a month? Well, for days in a month it depends not only on which month it is, but also on what type of calendar is used in the country you live in. What if, instead, we only use seconds to express time intervals? Then we can use metric system prefixes for writing large numbers of seconds in more easily comprehensible quantities. - A food recipe might explain that you need to let the brownies cook in the oven for two kiloseconds (that's two thousand seconds). - Perhaps you and your family would travel to somewhere exotic for two megaseconds (that's two million seconds). - And if you and your spouse were married for _a thousand million_ seconds, you would celebrate your one gigasecond anniversary. ~~~~exercism/note If we ever colonize Mars or some other planet, measuring time is going to get even messier. If someone says "year" do they mean a year on Earth or a year on Mars? The idea for this exercise came from the science fiction novel ["A Deepness in the Sky"][vinge-novel] by author Vernor Vinge. In it the author uses the metric system as the basis for time measurements. [vinge-novel]: https://www.tor.com/2017/08/03/science-fiction-with-something-for-everyone-a-deepness-in-the-sky-by-vernor-vinge/ ~~~~ ================================================ FILE: exercises/practice/gigasecond/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "enixander", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Gigasecond.kt" ], "test": [ "src/test/kotlin/GigasecondTest.kt" ], "example": [ ".meta/src/reference/kotlin/Gigasecond.kt" ] }, "blurb": "Given a moment, determine the moment that would be after a gigasecond has passed.", "source": "Chapter 9 in Chris Pine's online Learn to Program tutorial.", "source_url": "https://pine.fm/LearnToProgram/?Chapter=09" } ================================================ FILE: exercises/practice/gigasecond/.meta/src/reference/kotlin/Gigasecond.kt ================================================ import java.time.LocalDate import java.time.LocalDateTime data class Gigasecond(val initialDateTime: LocalDateTime) { constructor(initialDate: LocalDate): this(initialDate.atTime(0, 0)) val date = initialDateTime.plusSeconds(1_000_000_000) } ================================================ FILE: exercises/practice/gigasecond/.meta/tests.toml ================================================ [canonical-tests] # date only specification of time "92fbe71c-ea52-4fac-bd77-be38023cacf7" = true # second test for date only specification of time "6d86dd16-6f7a-47be-9e58-bb9fb2ae1433" = true # third test for date only specification of time "77eb8502-2bca-4d92-89d9-7b39ace28dd5" = true # full time specified "c9d89a7d-06f8-4e28-a305-64f1b2abc693" = true # full time with day roll-over "09d4e30e-728a-4b52-9005-be44a58d9eba" = true ================================================ FILE: exercises/practice/gigasecond/.meta/version ================================================ 2.0.0 ================================================ FILE: exercises/practice/gigasecond/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/gigasecond/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/gigasecond/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/gigasecond/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/gigasecond/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/gigasecond/src/main/kotlin/Gigasecond.kt ================================================ import java.time.LocalDateTime class Gigasecond { // TODO: Implement proper constructor val date: LocalDateTime = TODO("Implement this getter to complete the task") } ================================================ FILE: exercises/practice/gigasecond/src/test/kotlin/GigasecondTest.kt ================================================ import org.junit.Test import org.junit.Ignore import java.time.LocalDate import java.time.LocalDateTime import java.time.Month import kotlin.test.assertEquals class GigasecondTest { @Test fun `date only specification of time`() { val gigaSecond = Gigasecond(LocalDate.of(2011, Month.APRIL, 25)) assertEquals(LocalDateTime.of(2043, Month.JANUARY, 1, 1, 46, 40), gigaSecond.date) } @Ignore @Test fun `second test for date only specification of time`() { val gigaSecond = Gigasecond(LocalDate.of(1977, Month.JUNE, 13)) assertEquals(LocalDateTime.of(2009, Month.FEBRUARY, 19, 1, 46, 40), gigaSecond.date) } @Ignore @Test fun `third test for date only specification of time`() { val gigaSecond = Gigasecond(LocalDate.of(1959, Month.JULY, 19)) assertEquals(LocalDateTime.of(1991, Month.MARCH, 27, 1, 46, 40), gigaSecond.date) } @Ignore @Test fun `full time specified`() { val gigaSecond = Gigasecond(LocalDateTime.of(2015, Month.JANUARY, 24, 22, 0, 0)) assertEquals(LocalDateTime.of(2046, Month.OCTOBER, 2, 23, 46, 40), gigaSecond.date) } @Ignore @Test fun `full time with day roll-over`() { val gigaSecond = Gigasecond(LocalDateTime.of(2015, Month.JANUARY, 24, 23, 59, 59)) assertEquals(LocalDateTime.of(2046, Month.OCTOBER, 3, 1, 46, 39), gigaSecond.date) } } ================================================ FILE: exercises/practice/grade-school/.docs/instructions.md ================================================ # Instructions Given students' names along with the grade they are in, create a roster for the school. In the end, you should be able to: - Add a student's name to the roster for a grade: - "Add Jim to grade 2." - "OK." - Get a list of all students enrolled in a grade: - "Which students are in grade 2?" - "We've only got Jim right now." - Get a sorted list of all students in all grades. Grades should be sorted as 1, 2, 3, etc., and students within a grade should be sorted alphabetically by name. - "Who is enrolled in school right now?" - "Let me think. We have Anna, Barb, and Charlie in grade 1, Alex, Peter, and Zoe in grade 2, and Jim in grade 5. So the answer is: Anna, Barb, Charlie, Alex, Peter, Zoe, and Jim." Note that all our students only have one name (it's a small town, what do you want?), and each student cannot be added more than once to a grade or the roster. If a test attempts to add the same student more than once, your implementation should indicate that this is incorrect. ================================================ FILE: exercises/practice/grade-school/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "mikegehard", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "tehbilly", "uzilan" ], "files": { "solution": [ "src/main/kotlin/GradeSchool.kt" ], "test": [ "src/test/kotlin/SchoolTest.kt" ], "example": [ ".meta/src/reference/kotlin/GradeSchool.kt" ] }, "blurb": "Given students' names along with the grade that they are in, create a roster for the school.", "source": "A pairing session with Phil Battos at gSchool" } ================================================ FILE: exercises/practice/grade-school/.meta/src/reference/kotlin/GradeSchool.kt ================================================ class School { private val database = mutableMapOf>() fun add(student: String, grade: Int) { database[grade] = (grade(grade) + student).sorted() } fun grade(grade: Int) = database[grade] ?: listOf() fun roster() = database.toSortedMap().map { it.value }.flatten() } ================================================ FILE: exercises/practice/grade-school/.meta/tests.toml ================================================ [canonical-tests] # Adding a student adds them to the sorted roster "6d0a30e4-1b4e-472e-8e20-c41702125667" = true # Adding more student adds them to the sorted roster "233be705-dd58-4968-889d-fb3c7954c9cc" = true # Adding students to different grades adds them to the same sorted roster "75a51579-d1d7-407c-a2f8-2166e984e8ab" = true # Roster returns an empty list if there are no students enrolled "a3f0fb58-f240-4723-8ddc-e644666b85cc" = true # Student names with grades are displayed in the same sorted roster "180a8ff9-5b94-43fc-9db1-d46b4a8c93b6" = true # Grade returns the students in that grade in alphabetical order "1bfbcef1-e4a3-49e8-8d22-f6f9f386187e" = true # Grade returns an empty list if there are no students in that grade "5e67aa3c-a3c6-4407-a183-d8fe59cd1630" = true ================================================ FILE: exercises/practice/grade-school/.meta/version ================================================ 1.0.1 ================================================ FILE: exercises/practice/grade-school/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/grade-school/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/grade-school/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/grade-school/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/grade-school/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/grade-school/src/main/kotlin/GradeSchool.kt ================================================ class School { fun add(student: String, grade: Int) { TODO("Implement this function to complete the task") } fun grade(grade: Int): List { TODO("Implement this function to complete the task") } fun roster(): List { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/grade-school/src/test/kotlin/SchoolTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class SchoolTest { @Test fun `adding a student adds them to the sorted roster`() = students("Aimee" to 2) .everyone() .shouldBe(listOf("Aimee")) @Ignore @Test fun `adding more student adds them to the sorted roster`() = students( "Blair" to 2, "James" to 2, "Paul" to 2 ) .everyone() .shouldBe(listOf("Blair", "James", "Paul")) @Ignore @Test fun `adding students to different grades adds them to the same sorted roster`() = students( "Chelsea" to 3, "Logan" to 7 ) .everyone() .shouldBe(listOf("Chelsea", "Logan")) @Ignore @Test fun `roster returns an empty list if there are no students enrolled`() = students() .everyone() .shouldBe(listOf()) @Ignore @Test fun `student names with grades are displayed in the same sorted roster`() = students( "Peter" to 2, "Anna" to 1, "Barb" to 1, "Zoe" to 2, "Alex" to 2, "Jim" to 3, "Charlie" to 1 ) .everyone() .shouldBe(listOf("Anna", "Barb", "Charlie", "Alex", "Peter", "Zoe", "Jim")) @Ignore @Test fun `grade returns the students in that grade in alphabetical order`() = students( "Franklin" to 5, "Bradley" to 5, "Jeff" to 1 ) .fromGrade(5) .shouldBe(listOf("Bradley", "Franklin")) @Ignore @Test fun `grade returns an empty list if there are no students in that grade`() = students() .fromGrade(1) .shouldBe(listOf()) } private class Students(vararg students: Pair) { private val school = School() init { students.forEach { school.add(it.first, it.second) } } fun fromGrade(grade: Int) = StudentNames(school.grade(grade)) fun everyone() = StudentNames(school.roster()) } private class StudentNames(private val names: List) { fun shouldBe(names: List) = assertEquals(names, this.names) } private fun students(vararg students: Pair) = Students(*students) ================================================ FILE: exercises/practice/grains/.approaches/bit-shifting/content.md ================================================ # Bit-shifting ```kotlin import java.math.BigInteger object Board { fun getGrainCountForSquare(number: Int) = if (number < 1 || number > 64) throw IllegalArgumentException("square must be between 1 and 64") else BigInteger.ONE.shiftLeft(number - 1) fun getTotalGrainCount() = BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE) } ``` An [object declaration][object] is used to define `Board` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `getGrainCountForSquare` or `getTotalGrainCount` methods. The `getGrainCountForSquare` method is implemented by an `if/else` expression. Although the function has multiple lines, it consists only of the one `if/else` expression, so it is defined using [single-expression function][single-expression-function] syntax, with the curly braces omitted from the function call and the return type [inferred][type-inference]. An `IllegalArgumentException` is thrown if the number is out of bounds. Otherwise, to calculate the grains on a square you can set a bit in the correct position of a [`BigInteger`][biginteger] value. To understand how this works, consider just two squares that are represented in binary bits as `00`. You use the [`BigInteger.shiftLeft()`][shiftleft] method to set `1` (i.e. [`BigInteger.ONE`][one]) at the position needed to make the correct decimal value. - To set the one grain on Square One you shift `1` for `0` positions to the left. So, if `square` is `1` for square One, you subtract `square` by `1` to get `0`, which will not move it any positions to the left. The result is binary `01`, which is decimal `1`. - To set the two grains on Square Two you shift `1` for `1` position to the left. So, if `square` is `2` for square Two, you subtract `square` by `1` to get `1`, which will move it `1` position to the left. The result is binary `10`, which is decimal `2`. | Square | Shift Left By | Binary Value | Decimal Value | | ------- | ------------- | ------------ | ------------- | | 1 | 0 | 0001 | 1 | | 2 | 1 | 0010 | 2 | | 3 | 2 | 0100 | 4 | | 4 | 3 | 1000 | 8 | For `getTotalGrainCount` we want all of the 64 bits set to `1` to get the sum of grains on all sixty-four squares. The easy way to do this is to set the 65th bit to `1` and then subtract `1`. To go back to our two-square example, if we can grow to three squares, then we can shift `BigInteger.ONE` two positions to the left for binary `100`, which is decimal `4`. By subtracting `1` we get `3`, which is the total amount of grains on the two squares. | Square | Binary Value | Decimal Value | | ------- | ------------ | ------------- | | 3 | 0100 | 4 | | Square | Sum Binary Value | Sum Decimal Value | | ------- | ---------------- | ----------------- | | 1 | 0001 | 1 | | 2 | 0011 | 3 | [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [single-expression-function]: https://kotlinlang.org/docs/functions.html#single-expression-functions [type-inference]: https://kotlinlang.org/spec/type-inference.html [biginteger]: https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html [shiftleft]: https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html#shiftLeft(int) [one]: https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html#ONE ================================================ FILE: exercises/practice/grains/.approaches/bit-shifting/snippet.txt ================================================ fun getGrainCountForSquare(number: Int) = if (number < 1 || number > 64) throw IllegalArgumentException("square must be between 1 and 64") else BigInteger.ONE.shiftLeft(number - 1) fun getTotalGrainCount() = BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE) ================================================ FILE: exercises/practice/grains/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "4c786343-22f8-493f-8cb8-9c313f81ab59", "slug": "bit-shifting", "title": "Bit-shifting", "blurb": "Use bit-shifting to raise 2 by a specified power.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/grains/.approaches/introduction.md ================================================ # Introduction There are various idiomatic approaches to solve Grains. One approach can use `BigInteger` bit-shifting calculate the number on grains on a square. ## General guidance The key to solving Grains is to focus on each square having double the amount of grains as the square before it. This means that the amount of grains grows exponentially. The first square has one grain, which is `2` to the power of `0`. The second square has two grains, which is `2` to the power of `1`. The third square has four grains, which is `2` to the power of `2`. You can see that the exponent, or power, that `2` is raised by is always one less than the square number. | Square | Power | Value | | ------ | ----- | ----------------------- | | 1 | 0 | 2 to the power of 0 = 1 | | 2 | 1 | 2 to the power of 1 = 2 | | 3 | 2 | 2 to the power of 2 = 4 | | 4 | 3 | 2 to the power of 3 = 8 | ## Approach: Bit-shifting ```kotlin import java.math.BigInteger object Board { fun getGrainCountForSquare(number: Int) = if (number < 1 || number > 64) throw IllegalArgumentException("square must be between 1 and 64") else BigInteger.ONE.shiftLeft(number - 1) fun getTotalGrainCount() = BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE) } ``` For more information, check the [Bit-shifting approach][approach-bit-shifting]. [approach-bit-shifting]: https://exercism.org/tracks/kotlin/exercises/grains/approaches/bit-shifting ================================================ FILE: exercises/practice/grains/.docs/instructions.md ================================================ # Instructions Calculate the number of grains of wheat on a chessboard. A chessboard has 64 squares. Square 1 has one grain, square 2 has two grains, square 3 has four grains, and so on, doubling each time. Write code that calculates: - the number of grains on a given square - the total number of grains on the chessboard ================================================ FILE: exercises/practice/grains/.docs/introduction.md ================================================ # Introduction There once was a wise servant who saved the life of a prince. The king promised to pay whatever the servant could dream up. Knowing that the king loved chess, the servant told the king he would like to have grains of wheat. One grain on the first square of a chessboard, with the number of grains doubling on each successive square. ================================================ FILE: exercises/practice/grains/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Grains.kt" ], "test": [ "src/test/kotlin/BoardTest.kt" ], "example": [ ".meta/src/reference/kotlin/Grains.kt" ] }, "blurb": "Calculate the number of grains of wheat on a chessboard given that the number on each square doubles.", "source": "The CodeRanch Cattle Drive, Assignment 6", "source_url": "https://web.archive.org/web/20240908084142/https://coderanch.com/wiki/718824/Grains" } ================================================ FILE: exercises/practice/grains/.meta/src/reference/kotlin/Grains.kt ================================================ import java.math.BigInteger private const val SQUARE_COUNT = 64 private const val INVALID_SQUARE_NUMBER_MESSAGE = "Only integers between 1 and $SQUARE_COUNT (inclusive) are allowed" object Board { fun getGrainCountForSquare(number: Int): BigInteger { require(number > 0) { INVALID_SQUARE_NUMBER_MESSAGE } require(number <= SQUARE_COUNT) { INVALID_SQUARE_NUMBER_MESSAGE } return BigInteger.valueOf(2).pow(number - 1) } fun getTotalGrainCount(): BigInteger { return (1..SQUARE_COUNT) .map { getGrainCountForSquare(it) } .reduce { i1, i2 -> i1.add(i2) } } } ================================================ FILE: exercises/practice/grains/.meta/tests.toml ================================================ [canonical-tests] # 1 "9fbde8de-36b2-49de-baf2-cd42d6f28405" = true # 2 "ee1f30c2-01d8-4298-b25d-c677331b5e6d" = true # 3 "10f45584-2fc3-4875-8ec6-666065d1163b" = true # 4 "a7cbe01b-36f4-4601-b053-c5f6ae055170" = true # 16 "c50acc89-8535-44e4-918f-b848ad2817d4" = true # 32 "acd81b46-c2ad-4951-b848-80d15ed5a04f" = true # 64 "c73b470a-5efb-4d53-9ac6-c5f6487f227b" = true # square 0 raises an exception "1d47d832-3e85-4974-9466-5bd35af484e3" = true # negative square raises an exception "61974483-eeb2-465e-be54-ca5dde366453" = true # square greater than 64 raises an exception "a95e4374-f32c-45a7-a10d-ffec475c012f" = true # returns the total number of grains on the board "6eb07385-3659-4b45-a6be-9dc474222750" = true ================================================ FILE: exercises/practice/grains/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/grains/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/grains/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/grains/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/grains/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/grains/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/grains/src/main/kotlin/Grains.kt ================================================ import java.math.BigInteger object Board { fun getGrainCountForSquare(number: Int): BigInteger { TODO("Implement this function to complete the task") } fun getTotalGrainCount(): BigInteger { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/grains/src/test/kotlin/BoardTest.kt ================================================ import org.junit.Ignore import org.junit.Test import java.math.BigInteger import kotlin.test.assertEquals class BoardTest { @Test fun `per square - 1`() = assertGrainsEqual(1, 1) @Ignore @Test fun `per square - 2`() = assertGrainsEqual(2, 2) @Ignore @Test fun `per square - 3`() = assertGrainsEqual(3, 4) @Ignore @Test fun `per square - 4`() = assertGrainsEqual(4, 8) @Ignore @Test fun `per square - 16`() = assertGrainsEqual(16, 32768) @Ignore @Test fun `per square - 32`() = assertGrainsEqual(32, 2147483648) @Ignore @Test fun `per square - 64`() = assertGrainsEqual(64, "9223372036854775808") @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid input - square 0`() { grains(0) } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid input - negative square`() { grains(-1) } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid input - square after 64`() { grains(65) } @Ignore @Test fun `total - all grains on board`() { assertEquals(BigInteger("18446744073709551615"), Board.getTotalGrainCount()) } } private fun assertGrainsEqual(cell: Int, expectation: String) = assertEquals(BigInteger(expectation), grains(cell)) private fun assertGrainsEqual(cell: Int, expectation: Long) = assertEquals(BigInteger.valueOf(expectation), grains(cell)) private fun grains(cell: Int) = Board.getGrainCountForSquare(cell) ================================================ FILE: exercises/practice/hamming/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "edb06fc9-9d11-4102-af5f-d3d2912b64df", "slug": "zip-count", "title": "zip with count", "blurb": "Use zip with count to iterate to the answer.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/hamming/.approaches/introduction.md ================================================ # Introduction There are several ways to solve Hamming. One approach is to use [`zip`][zip] with [`count`][count]. ## Approach: `zip` with `count` ```kotlin object Hamming { fun compute(leftStrand: String, rightStrand: String) = if (leftStrand.length != rightStrand.length) throw IllegalArgumentException("left and right strands must be of equal length") else (leftStrand zip rightStrand).count { it.first != it.second } } ``` For more information, check the [`zip` with `count` approach][approach-zip-count]. [approach-zip-count]: https://exercism.org/tracks/kotlin/exercises/hamming/approaches/zip-count [zip]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/zip.html [count]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/count.html ================================================ FILE: exercises/practice/hamming/.approaches/zip-count/content.md ================================================ # `zip` with `count` ```kotlin object Hamming { fun compute(leftStrand: String, rightStrand: String) = if (leftStrand.length != rightStrand.length) throw IllegalArgumentException("left and right strands must be of equal length") else (leftStrand zip rightStrand).count { it.first != it.second } } ``` An [object declaration][object] is used to define `Hamming` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `compute` method. The `compute` method is implemented by an `if/else` expression. Although the function has multiple lines, it consists only of the one `if/else` expression, so it is defined using [single-expression function][single-expression-function] syntax, with the curly braces omitted from the function call and the return type [inferred][type-inference]. An `IllegalArgumentException` is thrown if the two input `String`s are not the same length. Otherwise, the [`zip`][zip] function is used to make a sequence of [`Pair`][pair] values of the characters at the same index in both input `String`s. Since `zip` is marked as an [`infix`][infix] function, it can be called between the two strands (i.e. between the left receiver and the right parameter), as well as called `leftStrand.zip(rightStrand)`. Which to use is a matter of stylistic preference. The [`count`][count] function iterates the `Pair` values and uses the [`it`][it] keyword to count the `Pair` values that meet the Boolean condition of the first value in the current `Pair` not being equal to the second value in the `Pair`. Finally, the `compute` function returns the result of calling `count` on the zipped `Pair` values. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [single-expression-function]: https://kotlinlang.org/docs/functions.html#single-expression-functions [type-inference]: https://kotlinlang.org/spec/type-inference.html [zip]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/zip.html [count]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/count.html [pair]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/ [infix]: https://kotlinlang.org/docs/functions.html#infix-notation [it]: https://kotlinlang.org/docs/lambdas.html#it-implicit-name-of-a-single-parameter ================================================ FILE: exercises/practice/hamming/.approaches/zip-count/snippet.txt ================================================ object Hamming { fun compute(leftStrand: String, rightStrand: String) = if (leftStrand.length != rightStrand.length) throw IllegalArgumentException("left and right strands must be of equal length") else (leftStrand zip rightStrand).count { it.first != it.second } } ================================================ FILE: exercises/practice/hamming/.docs/instructions.md ================================================ # Instructions Calculate the Hamming distance between two DNA strands. We read DNA using the letters C, A, G and T. Two strands might look like this: GAGCCTACTAACGGGAT CATCGTAATGACGGCCT ^ ^ ^ ^ ^ ^^ They have 7 differences, and therefore the Hamming distance is 7. ## Implementation notes The Hamming distance is only defined for sequences of equal length, so an attempt to calculate it between sequences of different lengths should not work. ================================================ FILE: exercises/practice/hamming/.docs/introduction.md ================================================ # Introduction Your body is made up of cells that contain DNA. Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime! When cells divide, their DNA replicates too. Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. If we compare two strands of DNA and count the differences between them, we can see how many mistakes occurred. This is known as the "Hamming distance". The Hamming distance is useful in many areas of science, not just biology, so it's a nice phrase to be familiar with :) ================================================ FILE: exercises/practice/hamming/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "ErikSchierboom", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Hamming.kt" ], "test": [ "src/test/kotlin/HammingTest.kt" ], "example": [ ".meta/src/reference/kotlin/Hamming.kt" ] }, "blurb": "Calculate the Hamming distance between two DNA strands.", "source": "The Calculating Point Mutations problem at Rosalind", "source_url": "https://rosalind.info/problems/hamm/" } ================================================ FILE: exercises/practice/hamming/.meta/src/reference/kotlin/Hamming.kt ================================================ object Hamming { fun compute(leftStrand: String, rightStrand: String): Int { require(leftStrand.length == rightStrand.length) { "left and right strands must be of equal length" } val commonPairs = leftStrand.zip(rightStrand) return commonPairs.count { it.first != it.second } } } ================================================ FILE: exercises/practice/hamming/.meta/tests.toml ================================================ [canonical-tests] # empty strands "f6dcb64f-03b0-4b60-81b1-3c9dbf47e887" = true # single letter identical strands "54681314-eee2-439a-9db0-b0636c656156" = true # single letter different strands "294479a3-a4c8-478f-8d63-6209815a827b" = true # long identical strands "9aed5f34-5693-4344-9b31-40c692fb5592" = true # long different strands "cd2273a5-c576-46c8-a52b-dee251c3e6e5" = true # disallow first strand longer "919f8ef0-b767-4d1b-8516-6379d07fcb28" = true # disallow second strand longer "8a2d4ed0-ead5-4fdd-924d-27c4cf56e60e" = true # disallow left empty strand "5dce058b-28d4-4ca7-aa64-adfe4e17784c" = true # disallow right empty strand "38826d4b-16fb-4639-ac3e-ba027dec8b5f" = true ================================================ FILE: exercises/practice/hamming/.meta/version ================================================ 2.3.0 ================================================ FILE: exercises/practice/hamming/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/hamming/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/hamming/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/hamming/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/hamming/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/hamming/src/main/kotlin/Hamming.kt ================================================ object Hamming { fun compute(leftStrand: String, rightStrand: String): Int { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/hamming/src/test/kotlin/HammingTest.kt ================================================ import org.junit.Test import org.junit.Ignore import org.junit.Rule import org.junit.rules.ExpectedException import kotlin.test.assertEquals class HammingTest { @Rule @JvmField var expectedException: ExpectedException = ExpectedException.none() @Test fun `empty strands`() { assertEquals(0, Hamming.compute("", "")) } @Ignore @Test fun `single letter identical strands`() { assertEquals(0, Hamming.compute("A", "A")) } @Ignore @Test fun `single letter different strands`() { assertEquals(1, Hamming.compute("G", "T")) } @Ignore @Test fun `long identical strands`() { assertEquals(0, Hamming.compute("GGACTGAAATCTG", "GGACTGAAATCTG")) } @Ignore @Test fun `long different strands`() { assertEquals(9, Hamming.compute("GGACGGATTCTG", "AGGACGGATTCT")) } @Ignore @Test fun `disallow first strand longer`() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("left and right strands must be of equal length") Hamming.compute("AATG", "AAA") } @Ignore @Test fun `disallow second strand longer`() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("left and right strands must be of equal length") Hamming.compute("ATA", "AGTG") } } ================================================ FILE: exercises/practice/hello-world/.docs/instructions.append.md ================================================ # Instructions append Since this is your first Kotlin exercise, we've included a detailed TUTORIAL.md file that guides you through your solution. Check it out for tips and assistance! ================================================ FILE: exercises/practice/hello-world/.docs/instructions.md ================================================ # Instructions The classical introductory exercise. Just say "Hello, World!". ["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment. The objectives are simple: - Modify the provided code so that it produces the string "Hello, World!". - Run the test suite and make sure that it succeeds. - Submit your solution and check it at the website. If everything goes well, you will be ready to fetch your first real exercise. [hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program ================================================ FILE: exercises/practice/hello-world/.meta/config.json ================================================ { "authors": [ "cswagner" ], "contributors": [ "bneevan", "dector", "HawkiesZA", "jtigger", "katrinleinweber", "kytrinyx", "lihofm", "mdowds", "mikegehard", "Mouzourides", "nithia", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "sup95", "uzilan" ], "files": { "solution": [ "src/main/kotlin/HelloWorld.kt" ], "test": [ "src/test/kotlin/HelloWorldTest.kt" ], "example": [ ".meta/src/reference/kotlin/HelloWorld.kt" ] }, "blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".", "source": "This is an exercise to introduce users to using Exercism", "source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program" } ================================================ FILE: exercises/practice/hello-world/.meta/src/reference/kotlin/HelloWorld.kt ================================================ fun hello(): String { return "Hello, World!" } ================================================ FILE: exercises/practice/hello-world/.meta/tests.toml ================================================ [canonical-tests] # Say Hi! "af9ffe10-dc13-42d8-a742-e7bdafac449d" = true ================================================ FILE: exercises/practice/hello-world/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/hello-world/TUTORIAL.md ================================================ # Tutorial NOTE: You can also view the HTML version of this file here: * [Introduction](#introduction) * [Exercise Structure](#exercise-structure) * [Solving "Hello, World!"](#solving-hello-world) * [Submitting your first iteration](#submitting-your-first-iteration) * [Next Steps](#next-steps) ---- # Introduction Welcome to the first exercise on the Kotlin track! This is a step-by-step guide to solving this exercise. Each exercise comes with a set of tests. The first pass through the exercise is about getting all of the tests to pass, one at a time. If you have not installed the Java Development Kit and Gradle, you must do so now. For help with this, see: https://exercism.org/docs/tracks/kotlin/installation ---- This guide picks-up where [Running the Tests (in Kotlin)](https://exercism.org/docs/tracks/kotlin/tests) left off. If you haven't reviewed those instructions, do so now. The following instructions work equally well on Windows, macOS and Linux. # Exercise Structure When you fetch a new Kotlin exercise, you will receive: * __one or more test files__ (always). These live in the `src/test/kotlin` directory and define a set of tests that our solution must satisfy before we can safely declare that it is working. * __one or more starter files__ (initially). If provided, these live in the `src/main/kotlin` directory and define shells of the classes you will need in order to solve the current problem. # Solving "Hello World!" ## Step 1: Run the tests against the starter solution Use Gradle to run the tests: ``` $ gradle test ``` This command does a lot and displays a bunch of stuff. Let's break it down... ``` :compileKotlin w: /Users/jtigger/exercism/exercises/kotlin/hello-world/src/main/kotlin/HelloWorld.kt: (1, 11): Parameter 'name' is never used :compileJava UP-TO-DATE :copyMainKotlinClasses :processResources UP-TO-DATE :classes UP-TO-DATE ``` Each line that begins with a colon (like `:compileKotlin`) is Gradle telling us that it's starting that task. The first five tasks are about compiling the source code of our *solution*. We've done you a favor and included just enough code for the solution that it compiles. When a task is successful, it generally does not output anything. This is why `:copyMainKotlinClasses` does not produce any additional output. A task may succeed but warn of a potential problem. This is what we see from `:compileKotlin`. The Kotlin compiler tells us that on line 1, 11 characters in of the `HelloWorld.kt` file, there is a parameter called `name` that was declared but never used. Usually, warnings _are_ helpful and should be heeded. We'll address this warning soon enough, but we're okay for now. The next five tasks are about compiling source code of the *tests*. ``` :compileTestKotlin :compileTestJava UP-TO-DATE :copyTestKotlinClasses :processTestResources UP-TO-DATE :testClasses UP-TO-DATE ``` ... with both sets of source code successfully compiled, Gradle turns to running the task you asked it to: executing the tests against the solution. ``` :test HelloWorldTest > helloWorldTest FAILED org.junit.ComparisonFailure: expected:<[Hello, World]!> but was:<[Goodbye, Mars]!> at org.junit.Assert.assertEquals(Assert.java:117) at kotlin.test.junit.JUnitAsserter.assertEquals(JUnitSupport.kt:32) at kotlin.test.AssertionsKt__AssertionsKt.assertEquals(Assertions.kt:63) at kotlin.test.AssertionsKt.assertEquals(Unknown Source) at kotlin.test.AssertionsKt__AssertionsKt.assertEquals$default(Assertions.kt:62) at kotlin.test.AssertionsKt.assertEquals$default(Unknown Source) at HelloWorldTest.helloWorldTest(HelloWorldTest.kt:8) 1 test completed, 1 failed :test FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':test'. > There were failing tests. See the report at: file:///Users/jtigger/exercism/exercises/kotlin/hello-world/build/reports/tests/index.html * Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. BUILD FAILED Total time: 7.473 secs ``` Seeing the word "fail" might give you the impression you've done something horribly wrong! You haven't. It's a whole lot of noise over a single test not passing. Let's focus in on the important bits: ``` HelloWorldTest > helloWorldTest FAILED org.junit.ComparisonFailure: expected:<[Hello, World!]> but was:<[Goodbye, Mars]!> ``` ...is read: "Within the test class named `HelloWorldTest`, the test method `helloWorldTest` did not pass because the solution did not satisfy an assertion. Apparently, we expected to see the string 'Hello, World!' but a blank string was returned instead. The last line of the stack trace tells us exactly where this unsatisfied assertion lives: ``` at HelloWorldTest.helloWorldTest(HelloWorldTest.kt:8) ``` Looks like the scene of the crime is on line 8 in the test file. Knowing these two facts, 1. the return value was not what was expected, and 2. the failure was on line 8 of the test, we can turn this failure into success. ## Step 2: Fix the Test! In your favorite text editor, open `src/test/kotlin/HelloWorldTest.kt` and go to line 8. ```kotlin assertEquals("Hello, World!", hello()) ``` The test is expecting that `hello()`, returns "Hello, World!". Instead, `hello()` is returning `"Goodbye, Mars!"`. Let's fix that. Open `src/main/kotlin/HelloWorld.kt`. ```kotlin fun hello(): String { return "Goodbye, Mars!" } ``` Let's change that to return the expected string: ```kotlin fun hello(): String { return "Hello, World!" } ``` Save the file and run the tests again: ``` $ gradle test :compileKotlin :compileJava UP-TO-DATE :copyMainKotlinClasses :processResources UP-TO-DATE :classes UP-TO-DATE :compileTestKotlin :compileTestJava UP-TO-DATE :copyTestKotlinClasses UP-TO-DATE :processTestResources UP-TO-DATE :testClasses UP-TO-DATE :test HelloWorldTest > helloWorldTest PASSED BUILD SUCCESSFUL Total time: 7.318 secs ``` "BUILD SUCCESSFUL"! Woohoo! :) You can see that `helloWorldTest()` test is now passing. Congratulations! # Submitting your first iteration With a working solution that we've reviewed, we're ready to submit it to exercism.io. ``` $ exercism submit src/main/kotlin/HelloWorld.kt ``` # Next Steps From here, there are a number of paths you can take. ## Move on to another exercise There are many more exercises you can practice with. Grab another one from the [Kotlin track](https://exercism.org/tracks/kotlin). ## Review (and comment on) others' submissions to this exercise The heart of Exercism is the conversations about coding practices. It's definitely fun to practice, but engaging with others both in their attempts and your own is how you get feedback. That feedback can help point out what you're doing well and where you might need to improve. Some submissions will be nearly identical to yours; others will be completely different. Seeing both kinds can be instructive and interesting. Note that you can only view submissions of others for exercises you have completed yourself. This enriches the experience of reading others' code because you'll have your own experience of trying to solve the problem. Here's an up-to-date list of submissions on the Kotlin track: ## Submit another iteration You are also encouraged to consider additional "requirements" on a given exercise. For example, you could add a test or two that requires that the greeting use the capitalized form on the person's name, regardless of the case they used. In that situation, you'd: 1. add a new test setting up that new expectation, 2. implement that in the code (the same process we just went through together, above). 3. review your code for readability and refactor as you see fit. Exercism practitioners who "play" with each exercise — over trying to go as fast as they can through the stream of exercises — report deep rewards. ## Contribute to Exercism The entire of Exercism is Open Source and is the labor of love for more than 100 maintainers and many more contributors. A starting point to jumping in can be found here: ---- Regardless of what you decide to do next, we sincerely hope you learn and enjoy being part of this community. If at any time you need assistance do not hesitate to ask for help: Cheers! ================================================ FILE: exercises/practice/hello-world/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/hello-world/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/hello-world/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/hello-world/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/hello-world/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/hello-world/src/main/kotlin/HelloWorld.kt ================================================ fun hello(): String { return "Goodbye, Mars!" } ================================================ FILE: exercises/practice/hello-world/src/test/kotlin/HelloWorldTest.kt ================================================ import org.junit.Test import kotlin.test.assertEquals class HelloWorldTest { @Test fun helloWorldTest() { assertEquals("Hello, World!", hello()) } } ================================================ FILE: exercises/practice/hexadecimal/.docs/instructions.md ================================================ # Instructions Convert a hexadecimal number, represented as a string (e.g. "10af8c"), to its decimal equivalent using first principles (i.e. no, you may not use built-in or external libraries to accomplish the conversion). On the web we use hexadecimal to represent colors, e.g. green: 008000, teal: 008080, navy: 000080). The program should handle invalid hexadecimal strings. ================================================ FILE: exercises/practice/hexadecimal/.meta/config.json ================================================ { "blurb": "Convert a hexadecimal number, represented as a string (e.g. \"10af8c\"), to its decimal equivalent using first principles (i.e. no, you may not use built-in or external libraries to accomplish the conversion).", "authors": ["sdavids13"], "contributors": [ "dector", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": ["src/main/kotlin/Hexadecimal.kt"], "test": ["src/test/kotlin/HexadecimalTest.kt"], "example": [".meta/src/reference/kotlin/Hexadecimal.kt"] }, "source": "All of Computer Science", "source_url": "http://www.wolframalpha.com/examples/NumberBases.html" } ================================================ FILE: exercises/practice/hexadecimal/.meta/src/reference/kotlin/Hexadecimal.kt ================================================ object Hexadecimal { private val hexChars = ('0'..'9') + ('a'..'f') fun toDecimal(s: String): Int { return s.lowercase().fold(0) { accum, char -> when (char) { in hexChars -> hexChars.indexOf(char) + (accum * 16) else -> return 0 } } } } ================================================ FILE: exercises/practice/hexadecimal/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/hexadecimal/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/hexadecimal/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/hexadecimal/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/hexadecimal/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/hexadecimal/src/main/kotlin/Hexadecimal.kt ================================================ object Hexadecimal { fun toDecimal(s: String): Int { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/hexadecimal/src/test/kotlin/HexadecimalTest.kt ================================================ import org.junit.Test import org.junit.Ignore import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals @RunWith(Parameterized::class) class HexadecimalTest(val input: String, val expectedOutput: Int) { companion object { @JvmStatic @Parameterized.Parameters(name = "{index}: binary({0})={1}") fun data() = listOf( arrayOf("1", 1), arrayOf("c", 12), arrayOf("10", 16), arrayOf("af", 175), arrayOf("AF", 175), arrayOf("100", 256), arrayOf("19ace", 105166), arrayOf("000000", 0), arrayOf("ffffff", 16777215), arrayOf("ffff00", 16776960), //Invalid input arrayOf("carrot1", 0), arrayOf("abc10z", 0), arrayOf("g1", 0) ) } @Test fun hexStringToInt() { assertEquals(expectedOutput, Hexadecimal.toDecimal(input)) } } ================================================ FILE: exercises/practice/isbn-verifier/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "addeaa3a-174d-45e4-9a50-47711b0bb097", "slug": "fold-when-let", "title": "fold, when, and let", "blurb": "Use fold and when with let to return the answer.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/isbn-verifier/.approaches/fold-when-let/content.md ================================================ # `fold` and `when` with `let` ```kotlin class IsbnVerifier { fun isValid(number: String) = number .fold(Pair(10, 0)) { (pos, sum), ch -> when { ch.isDigit() -> pos - 1 to sum + (ch.digitToInt() * pos) ch == 'X' && pos == 1 -> pos - 1 to sum + 10 ch == '-' -> pos to sum else -> -1 to sum } } .let { it.first == 0 && it.second % 11 == 0 } } ``` Since there is no object state that needs to change with each call of the `isValid` method, the `IsbnVerifier` class _could_ be defined as an [object][object], making it essentially a [singleton][singleton] object instantiation of the class. However, as of this writing, the tests call `isValid` using an empty constructor for `IsbnVerifier` (e.g. `IsbnVerifier().isValid(isbn)`) instead of calling `isValid` like a method on an object (e.g. `IsbnVerifier.isValid(isbn)`), which is why `IsbnVerifier` can't be defined as an `object`. The `isValid` function is implemented as a call of [`fold`][fold] chained to [`let`][let]. Although the `isValid` function has multiple lines, it consists only of the one expression resulting from the function chain, so it is defined using [single-expression function][single-expression-function] syntax, with the curly braces omitted from the `isValid` function call and the return type [inferred][type-inference]. The [`fold`][fold] method is called on the input `String`. Its accumulating value is initialized as a [`Pair`][pair] of values that represent the updating position and the calculating sum, with the position starting at `10`, and the `sum` starting with `0`. The [lambda][lambda] of `fold` takes the accumulating `Pair` as well as the character being iterated. Inside the lambda is a [`when`][when] expression to check the value of the current character being iterated. If the character is a digit, then the `when` returns the current position subtracted by `1`, and also returns the `sum` plus the character's numeric value multiplied by the current position. It returns the values as the accumulating `Pair` by using the [`to`][to] keyword. If the character is an `X` and the position is `1`, then the current position subtracted by `1` and the `sum` plus `10` are returned. If the character is a `-`, then the position and sum are returned as is. If none of those cases for the `when` are matched, then the character is illegal, so `-1` and the sum are returned. The `-1` is meant to make the final check for a valid position fail. After the fold has iterated all of the characters in the input string, the [`let`][let] function is used to check the values of the accumulating `Pair`. If the position is at `0` and the `sum` is evenly divided by `11`, then `true` is returned from `let`, otherwise, `false` is returned. The `isValid` function returns the result of calling `let`. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [fold]: https://kotlinlang.org/docs/collection-aggregate.html#fold-and-reduce [when]: https://kotlinlang.org/docs/control-flow.html#when-expression [let]: https://kotlinlang.org/docs/scope-functions.html#let [single-expression-function]: https://kotlinlang.org/docs/functions.html#single-expression-functions [type-inference]: https://kotlinlang.org/spec/type-inference.html [pair]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/ [to]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html [lambda]: https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions ================================================ FILE: exercises/practice/isbn-verifier/.approaches/fold-when-let/snippet.txt ================================================ .fold(Pair(10, 0)) { (pos, sum), ch -> when { ch.isDigit() -> pos - 1 to sum + (ch.digitToInt() * pos) ch == 'X' && pos == 1 -> pos - 1 to sum + 10 ch == '-' -> pos to sum else -> -1 to sum } } ================================================ FILE: exercises/practice/isbn-verifier/.approaches/introduction.md ================================================ # Introduction There are several ways to solve Isbn Verifier. One approach is to use [`fold`][fold] and [`when`][when] with [`let`][let]. ## Approach: `fold` and `when` with `let` ```kotlin class IsbnVerifier { fun isValid(number: String) = number .fold(Pair(10, 0)) { (pos, sum), ch -> when { ch.isDigit() -> pos - 1 to sum + (ch.digitToInt() * pos) ch == 'X' && pos == 1 -> pos - 1 to sum + 10 ch == '-' -> pos to sum else -> -1 to sum } } .let { it.first == 0 && it.second % 11 == 0 } } ``` For more information, check the [`fold` and `when` with `let` approach][approach-fold-when-let]. [approach-fold-when-let]: https://exercism.org/tracks/kotlin/exercises/isbn-verifier/approaches/fold-when-let [fold]: https://kotlinlang.org/docs/collection-aggregate.html#fold-and-reduce [when]: https://kotlinlang.org/docs/control-flow.html#when-expression [let]: https://kotlinlang.org/docs/scope-functions.html#let ================================================ FILE: exercises/practice/isbn-verifier/.docs/instructions.md ================================================ # Instructions The [ISBN-10 verification process][isbn-verification] is used to validate book identification numbers. These normally contain dashes and look like: `3-598-21508-8` ## ISBN The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). In the case the check character is an X, this represents the value '10'. These may be communicated with or without hyphens, and can be checked for their validity by the following formula: ```text (d₁ * 10 + d₂ * 9 + d₃ * 8 + d₄ * 7 + d₅ * 6 + d₆ * 5 + d₇ * 4 + d₈ * 3 + d₉ * 2 + d₁₀ * 1) mod 11 == 0 ``` If the result is 0, then it is a valid ISBN-10, otherwise it is invalid. ## Example Let's take the ISBN-10 `3-598-21508-8`. We plug it in to the formula, and get: ```text (3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0 ``` Since the result is 0, this proves that our ISBN is valid. ## Task Given a string the program should check if the provided string is a valid ISBN-10. Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN. The program should be able to verify ISBN-10 both with and without separating dashes. ## Caveats Converting from strings to numbers can be tricky in certain languages. Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). For instance `3-598-21507-X` is a valid ISBN-10. [isbn-verification]: https://en.wikipedia.org/wiki/International_Standard_Book_Number ================================================ FILE: exercises/practice/isbn-verifier/.meta/config.json ================================================ { "authors": [ "vmichalak" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/IsbnVerifier.kt" ], "test": [ "src/test/kotlin/IsbnVerifierTest.kt" ], "example": [ ".meta/src/reference/kotlin/IsbnVerifier.kt" ] }, "blurb": "Check if a given string is a valid ISBN-10 number.", "source": "Converting a string into a number and some basic processing utilizing a relatable real world example.", "source_url": "https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation" } ================================================ FILE: exercises/practice/isbn-verifier/.meta/src/reference/kotlin/IsbnVerifier.kt ================================================ class IsbnVerifier { fun isValid(number: String): Boolean { val value: String = number.replace("-", "") if(!Regex("""^(\d{9}[\dX])${'$'}""").matches(value)) { return false } return value.mapIndexed { i, c -> (10 - i) * when { c == 'X' && i == 9 -> 10 else -> Character.getNumericValue(c) } }.sum() % 11 == 0 } } ================================================ FILE: exercises/practice/isbn-verifier/.meta/tests.toml ================================================ [canonical-tests] # valid isbn number "0caa3eac-d2e3-4c29-8df8-b188bc8c9292" = true # invalid isbn check digit "19f76b53-7c24-45f8-87b8-4604d0ccd248" = true # valid isbn number with a check digit of 10 "4164bfee-fb0a-4a1c-9f70-64c6a1903dcd" = true # check digit is a character other than X "3ed50db1-8982-4423-a993-93174a20825c" = true # invalid character in isbn "c19ba0c4-014f-4dc3-a63f-ff9aefc9b5ec" = true # X is only valid as a check digit "28025280-2c39-4092-9719-f3234b89c627" = true # valid isbn without separating dashes "f6294e61-7e79-46b3-977b-f48789a4945b" = true # isbn without separating dashes and X as check digit "185ab99b-3a1b-45f3-aeec-b80d80b07f0b" = true # isbn without check digit and dashes "7725a837-ec8e-4528-a92a-d981dd8cf3e2" = true # too long isbn and no dashes "47e4dfba-9c20-46ed-9958-4d3190630bdf" = true # too short isbn "737f4e91-cbba-4175-95bf-ae630b41fb60" = true # isbn without check digit "5458a128-a9b6-4ff8-8afb-674e74567cef" = true # check digit of X should not be used for 0 "70b6ad83-d0a2-4ca7-a4d5-a9ab731800f7" = true # empty isbn "94610459-55ab-4c35-9b93-ff6ea1a8e562" = true # input is 9 characters "7bff28d4-d770-48cc-80d6-b20b3a0fb46c" = true # invalid characters are not ignored "ed6e8d1b-382c-4081-8326-8b772c581fec" = true # input is too long but contains a valid isbn "fb5e48d8-7c03-4bfb-a088-b101df16fdc3" = true ================================================ FILE: exercises/practice/isbn-verifier/.meta/version ================================================ 2.7.0 ================================================ FILE: exercises/practice/isbn-verifier/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/isbn-verifier/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/isbn-verifier/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/isbn-verifier/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/isbn-verifier/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/isbn-verifier/src/main/kotlin/IsbnVerifier.kt ================================================ class IsbnVerifier { fun isValid(number: String): Boolean { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/isbn-verifier/src/test/kotlin/IsbnVerifierTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertFalse import kotlin.test.assertTrue class IsbnVerifierTest { @Test fun `valid - reguar isbn`() = assertValid("3-598-21508-8") @Ignore @Test fun `invalid - check digit`() = assertInvalid("3-598-21508-9") @Ignore @Test fun `valid - check digit is 10`() = assertValid("3-598-21507-X") @Ignore @Test fun `invalid - check digit is character other than X`() = assertInvalid("3-598-21507-A") @Ignore @Test fun `invalid - forbidden character`() = assertInvalid("3-598-P1581-X") @Ignore @Test fun `invalid - X is only valid as check digit`() = assertInvalid("3-598-2X507-9") @Ignore @Test fun `valid - without separating dashes`() = assertValid("3598215088") @Ignore @Test fun `valid - without separating dashes and X as check digit`() = assertValid("359821507X") @Ignore @Test fun `invalid - without check digit and dashes`() = assertInvalid("359821507") @Ignore @Test fun `invalid - too long and no dashes`() = assertInvalid("3598215078X") @Ignore @Test fun `invalid - too short`() = assertInvalid("00") @Ignore @Test fun `invalid - without check digit`() = assertInvalid("3-598-21507") @Ignore @Test fun `invalid - check digit of X is not used for 0`() = assertInvalid("3-598-21515-X") @Ignore @Test fun `invalid - empty`() = assertInvalid("") @Ignore @Test fun `invalid - input is 9 characters`() = assertInvalid("134456729") @Ignore @Test fun `invalid - prohibited characters are not ignored`() = assertInvalid("3132P34035") @Ignore @Test fun `invalid - too long but contains valid isbn`() = assertInvalid("98245726788") } private fun assertValid(isbn: String) = assertTrue(IsbnVerifier().isValid(isbn)) private fun assertInvalid(isbn: String) = assertFalse(IsbnVerifier().isValid(isbn)) ================================================ FILE: exercises/practice/isogram/.docs/instructions.md ================================================ # Instructions Determine if a word or phrase is an isogram. An isogram (also known as a "non-pattern word") is a word or phrase without a repeating letter, however spaces and hyphens are allowed to appear multiple times. Examples of isograms: - lumberjacks - background - downstream - six-year-old The word _isograms_, however, is not an isogram, because the s repeats. ================================================ FILE: exercises/practice/isogram/.meta/config.json ================================================ { "authors": [ "gandrianakis" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Isogram.kt" ], "test": [ "src/test/kotlin/IsogramTest.kt" ], "example": [ ".meta/src/reference/kotlin/Isogram.kt" ] }, "blurb": "Determine if a word or phrase is an isogram.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Isogram" } ================================================ FILE: exercises/practice/isogram/.meta/src/reference/kotlin/Isogram.kt ================================================ object Isogram { fun isIsogram(input: String): Boolean { val sanitizedInput = input.lowercase().replace("[.!?\\-\\s]".toRegex(), "") val charCounts = sanitizedInput.toList().countBy() return !charCounts.any { it.value > 1 } } } fun Iterable.countBy() : Map = this.countBy { it } fun Iterable.countBy(transformer: (T) -> M) : Map { val emptyMap = mapOf() return this.fold(emptyMap) {accumulator, item -> val transformedItem = transformer(item) accumulator + Pair(transformedItem, accumulator.getOrElse(transformedItem) { 0 } + 1) } } ================================================ FILE: exercises/practice/isogram/.meta/tests.toml ================================================ [canonical-tests] # empty string "a0e97d2d-669e-47c7-8134-518a1e2c4555" = true # isogram with only lower case characters "9a001b50-f194-4143-bc29-2af5ec1ef652" = true # word with one duplicated character "8ddb0ca3-276e-4f8b-89da-d95d5bae78a4" = true # word with one duplicated character from the end of the alphabet "6450b333-cbc2-4b24-a723-0b459b34fe18" = true # longest reported english isogram "a15ff557-dd04-4764-99e7-02cc1a385863" = true # word with duplicated character in mixed case "f1a7f6c7-a42f-4915-91d7-35b2ea11c92e" = true # word with duplicated character in mixed case, lowercase first "14a4f3c1-3b47-4695-b645-53d328298942" = true # hypothetical isogrammic word with hyphen "423b850c-7090-4a8a-b057-97f1cadd7c42" = true # hypothetical word with duplicated character following hyphen "93dbeaa0-3c5a-45c2-8b25-428b8eacd4f2" = true # isogram with duplicated hyphen "36b30e5c-173f-49c6-a515-93a3e825553f" = true # made-up name that is an isogram "cdabafa0-c9f4-4c1f-b142-689c6ee17d93" = true # duplicated character in the middle "5fc61048-d74e-48fd-bc34-abfc21552d4d" = true # same first and last characters "310ac53d-8932-47bc-bbb4-b2b94f25a83e" = true ================================================ FILE: exercises/practice/isogram/.meta/version ================================================ 1.7.0 ================================================ FILE: exercises/practice/isogram/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/isogram/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/isogram/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/isogram/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/isogram/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/isogram/src/main/kotlin/Isogram.kt ================================================ object Isogram { fun isIsogram(input: String): Boolean { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/isogram/src/test/kotlin/IsogramTest.kt ================================================ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals @RunWith(Parameterized::class) class IsogramTest(val input: String, val expectedOutput: Boolean) { companion object { @JvmStatic @Parameterized.Parameters(name = "{index}: isogram({0}) = {1}") fun data() = listOf( arrayOf("", true), arrayOf("isogram", true), arrayOf("eleven", false), arrayOf("zzyzx", false), arrayOf("subdermatoglyphic", true), arrayOf("Alphabet", false), arrayOf("alphAbet", false), arrayOf("thumbscrew-japingly", true), arrayOf("thumbscrew-jappingly", false), arrayOf("six-year-old", true), arrayOf("Emily Jung Schwartzkopf", true), arrayOf("accentor", false), arrayOf("angola", false) ) } @Test fun test() { assertEquals(expectedOutput, Isogram.isIsogram(input)) } } ================================================ FILE: exercises/practice/kindergarten-garden/.docs/instructions.md ================================================ # Instructions Your task is to, given a diagram, determine which plants each child in the kindergarten class is responsible for. There are 12 children in the class: - Alice, Bob, Charlie, David, Eve, Fred, Ginny, Harriet, Ileana, Joseph, Kincaid, and Larry. Four different types of seeds are planted: | Plant | Diagram encoding | | ------ | ---------------- | | Grass | G | | Clover | C | | Radish | R | | Violet | V | Each child gets four cups, two on each row: ```text [window][window][window] ........................ # each dot represents a cup ........................ ``` Their teacher assigns cups to the children alphabetically by their names, which means that Alice comes first and Larry comes last. Here is an example diagram representing Alice's plants: ```text [window][window][window] VR...................... RG...................... ``` In the first row, nearest the windows, she has a violet and a radish. In the second row she has a radish and some grass. Your program will be given the plants from left-to-right starting with the row nearest the windows. From this, it should be able to determine which plants belong to each student. For example, if it's told that the garden looks like so: ```text [window][window][window] VRCGVVRVCGGCCGVRGCVCGCGV VRCCCGCRRGVCGCRVVCVGCGCV ``` Then if asked for Alice's plants, it should provide: - Violets, radishes, violets, radishes While asking for Bob's plants would yield: - Clover, grass, clover, clover ================================================ FILE: exercises/practice/kindergarten-garden/.docs/introduction.md ================================================ # Introduction The kindergarten class is learning about growing plants. The teacher thought it would be a good idea to give the class seeds to plant and grow in the dirt. To this end, the children have put little cups along the window sills and planted one type of plant in each cup. The children got to pick their favorites from four available types of seeds: grass, clover, radishes, and violets. ================================================ FILE: exercises/practice/kindergarten-garden/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/KindergartenGarden.kt" ], "test": [ "src/test/kotlin/KindergartenGardenTest.kt" ], "example": [ ".meta/src/reference/kotlin/KindergartenGarden.kt" ] }, "blurb": "Given a diagram, determine which plants each child in the kindergarten class is responsible for.", "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", "source_url": "https://turing.edu" } ================================================ FILE: exercises/practice/kindergarten-garden/.meta/src/reference/kotlin/KindergartenGarden.kt ================================================ class KindergartenGarden(private val diagram: String) { val students = listOf( "Alice", "Bob", "Charlie", "David", "Eve", "Fred", "Ginny", "Harriet", "Ileana", "Joseph", "Kincaid", "Larry") val plants: Map = mapOf( 'V' to "violets", 'R' to "radishes", 'C' to "clover", 'G' to "grass") fun getPlantsOfStudent(student: String): List { val idx = students.indexOf(student) return diagram .split("\n") // split into two lines .map { it.substring(idx * 2, idx * 2 + 2) } // the two letters of that student in each line .joinToString("") // merge the two letters of each diagram line into one string .map { plants[it]!! } // lookup the plant names by the given letters } } ================================================ FILE: exercises/practice/kindergarten-garden/.meta/tests.toml ================================================ [canonical-tests] # garden with single student "1fc316ed-17ab-4fba-88ef-3ae78296b692" = true # different garden with single student "acd19dc1-2200-4317-bc2a-08f021276b40" = true # garden with two students "c376fcc8-349c-446c-94b0-903947315757" = true # second student's garden "2d620f45-9617-4924-9d27-751c80d17db9" = true # third student's garden "57712331-4896-4364-89f8-576421d69c44" = true # first student's garden "149b4290-58e1-40f2-8ae4-8b87c46e765b" = true # second student's garden "ba25dbbc-10bd-4a37-b18e-f89ecd098a5e" = true # second to last student's garden "6bb66df7-f433-41ab-aec2-3ead6e99f65b" = true # last student's garden "d7edec11-6488-418a-94e6-ed509e0fa7eb" = true ================================================ FILE: exercises/practice/kindergarten-garden/.meta/version ================================================ 1.1.1 ================================================ FILE: exercises/practice/kindergarten-garden/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/kindergarten-garden/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/kindergarten-garden/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/kindergarten-garden/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/kindergarten-garden/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/kindergarten-garden/src/main/kotlin/KindergartenGarden.kt ================================================ class KindergartenGarden(private val diagram: String) { fun getPlantsOfStudent(student: String): List { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/kindergarten-garden/src/test/kotlin/KindergartenGardenTest.kt ================================================ import kotlin.test.Test import kotlin.test.Ignore import kotlin.test.assertEquals class KindergartenGardenTest { @Test fun `single student`() { val student = "Alice" val diagram = "RC\nGG" val expected = listOf("radishes", "clover", "grass", "grass") assertEquals(expected, KindergartenGarden(diagram).getPlantsOfStudent(student)) } @Ignore @Test fun `single student2`() { val student = "Alice" val diagram = "VC\nRC" val expected = listOf("violets", "clover", "radishes", "clover") assertEquals(expected, KindergartenGarden(diagram).getPlantsOfStudent(student)) } @Ignore @Test fun `two students`() { val student = "Bob" val diagram = "VVCG\nVVRC" val expected = listOf("clover", "grass", "radishes", "clover") assertEquals(expected, KindergartenGarden(diagram).getPlantsOfStudent(student)) } @Ignore @Test fun `one garden second student`() { val student = "Bob" val diagram = "VVCCGG\nVVCCGG" val expected = listOf("clover", "clover", "clover", "clover") assertEquals(expected, KindergartenGarden(diagram).getPlantsOfStudent(student)) } @Ignore @Test fun `one garden third student`() { val student = "Charlie" val diagram = "VVCCGG\nVVCCGG" val expected = listOf("grass", "grass", "grass", "grass") assertEquals(expected, KindergartenGarden(diagram).getPlantsOfStudent(student)) } @Ignore @Test fun `full garden first student`() { val student = "Alice" val diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" val expected = listOf("violets", "radishes", "violets", "radishes") assertEquals(expected, KindergartenGarden(diagram).getPlantsOfStudent(student)) } @Ignore @Test fun `full garden second student`() { val student = "Bob" val diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" val expected = listOf("clover", "grass", "clover", "clover") assertEquals(expected, KindergartenGarden(diagram).getPlantsOfStudent(student)) } @Ignore @Test fun `full garden second to last student`() { val student = "Kincaid" val diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" val expected = listOf("grass", "clover", "clover", "grass") assertEquals(expected, KindergartenGarden(diagram).getPlantsOfStudent(student)) } @Ignore @Test fun `full garden last student`() { val student = "Larry" val diagram = "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV" val expected = listOf("grass", "violets", "clover", "violets") assertEquals(expected, KindergartenGarden(diagram).getPlantsOfStudent(student)) } } ================================================ FILE: exercises/practice/knapsack/.docs/instructions.md ================================================ # Instructions Your task is to determine which items to take so that the total value of her selection is maximized, taking into account the knapsack's carrying capacity. Items will be represented as a list of items. Each item will have a weight and value. All values given will be strictly positive. Lhakpa can take only one of each item. For example: ```text Items: [ { "weight": 5, "value": 10 }, { "weight": 4, "value": 40 }, { "weight": 6, "value": 30 }, { "weight": 4, "value": 50 } ] Knapsack Maximum Weight: 10 ``` For the above, the first item has weight 5 and value 10, the second item has weight 4 and value 40, and so on. In this example, Lhakpa should take the second and fourth item to maximize her value, which, in this case, is 90. She cannot get more than 90 as her knapsack has a weight limit of 10. ================================================ FILE: exercises/practice/knapsack/.docs/introduction.md ================================================ # Introduction Lhakpa is a [Sherpa][sherpa] mountain guide and porter. After months of careful planning, the expedition Lhakpa works for is about to leave. She will be paid the value she carried to the base camp. In front of her are many items, each with a value and weight. Lhakpa would gladly take all of the items, but her knapsack can only hold so much weight. [sherpa]: https://en.wikipedia.org/wiki/Sherpa_people#Mountaineering ================================================ FILE: exercises/practice/knapsack/.meta/config.json ================================================ { "authors": [ "lpizzinidev" ], "files": { "solution": [ "src/main/kotlin/Knapsack.kt" ], "test": [ "src/test/kotlin/KnapsackTest.kt" ], "example": [ ".meta/src/reference/kotlin/Knapsack.kt" ] }, "blurb": "Given a knapsack that can only carry a certain weight, determine which items to put in the knapsack in order to maximize their combined value.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Knapsack_problem" } ================================================ FILE: exercises/practice/knapsack/.meta/src/reference/kotlin/Knapsack.kt ================================================ data class Item(val weight: Int, val value: Int) fun knapsack(maximumWeight: Int, items: List): Int { val table = Array(items.size + 1) { IntArray(maximumWeight + 1) { 0 }} items.forEachIndexed { index, item -> for (c in 1..maximumWeight) { if (item.weight > c) { table[index+1][c] = table[index][c] } else { table[index+1][c] = Math.max( table[index][c], item.value + table[index][c-item.weight] ) } } } return table[items.size][maximumWeight] } ================================================ FILE: exercises/practice/knapsack/.meta/tests.toml ================================================ [canonical-tests] # no items "a4d7d2f0-ad8a-460c-86f3-88ba709d41a7" = true # one item, too heavy "1d39e98c-6249-4a8b-912f-87cb12e506b0" = true # five items (cannot be greedy by weight) "833ea310-6323-44f2-9d27-a278740ffbd8" = true # five items (cannot be greedy by value) "277cdc52-f835-4c7d-872b-bff17bab2456" = true # example knapsack "81d8e679-442b-4f7a-8a59-7278083916c9" = true # 8 items "f23a2449-d67c-4c26-bf3e-cde020f27ecc" = true # 15 items "7c682ae9-c385-4241-a197-d2fa02c81a11" = true ================================================ FILE: exercises/practice/knapsack/.meta/version ================================================ 1.0.0 ================================================ FILE: exercises/practice/knapsack/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/knapsack/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/knapsack/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/knapsack/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/knapsack/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/knapsack/src/main/kotlin/Knapsack.kt ================================================ data class Item(val weight: Int, val value: Int) fun knapsack(maximumWeight: Int, items: List): Int { TODO("Implement this function to complete the task") } ================================================ FILE: exercises/practice/knapsack/src/test/kotlin/KnapsackTest.kt ================================================ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.Ignore class KnapsackTest { @Test fun `no items`() = assertEquals(0, knapsack(100, listOf())) @Ignore @Test fun `one item, too heavy`() { val items = listOf(Item(100, 1)) assertEquals(0, knapsack(10, items)) } @Ignore @Test fun `five items (cannot be greedy by weight)`() { val items = listOf( Item(2, 5), Item(2, 5), Item(2, 5), Item(2, 5), Item(10, 21) ) assertEquals(21, knapsack(10, items)) } @Ignore @Test fun `five items (cannot be greedy by value)`() { val items = listOf( Item(2, 20), Item(2, 20), Item(2, 20), Item(2, 20), Item(10, 50) ) assertEquals(80, knapsack(10, items)) } @Ignore @Test fun `example knapsack`() { val items = listOf( Item(5, 10), Item(4, 40), Item(6, 30), Item(4, 50) ) assertEquals(90, knapsack(10, items)) } @Ignore @Test fun `8 items`() { val items = listOf( Item(25, 350), Item(35, 400), Item(45, 450), Item(5, 20), Item(25, 70), Item(3, 8), Item(2, 5), Item(2, 5) ) assertEquals(900, knapsack(104, items)) } @Ignore @Test fun `15 items`() { val items = listOf( Item(70, 135), Item(73, 139), Item(77, 149), Item(80, 150), Item(82, 156), Item(87, 163), Item(90, 173), Item(94, 184), Item(98, 192), Item(106, 201), Item(110, 210), Item(113, 214), Item(115, 221), Item(118, 229), Item(120, 240) ) assertEquals(1458, knapsack(750, items)) } } ================================================ FILE: exercises/practice/largest-series-product/.docs/instructions.md ================================================ # Instructions Your task is to look for patterns in the long sequence of digits in the encrypted signal. The technique you're going to use here is called the largest series product. Let's define a few terms, first. - **input**: the sequence of digits that you need to analyze - **series**: a sequence of adjacent digits (those that are next to each other) that is contained within the input - **span**: how many digits long each series is - **product**: what you get when you multiply numbers together Let's work through an example, with the input `"63915"`. - To form a series, take adjacent digits in the original input. - If you are working with a span of `3`, there will be three possible series: - `"639"` - `"391"` - `"915"` - Then we need to calculate the product of each series: - The product of the series `"639"` is 162 (`6 × 3 × 9 = 162`) - The product of the series `"391"` is 27 (`3 × 9 × 1 = 27`) - The product of the series `"915"` is 45 (`9 × 1 × 5 = 45`) - 162 is bigger than both 27 and 45, so the largest series product of `"63915"` is from the series `"639"`. So the answer is **162**. ================================================ FILE: exercises/practice/largest-series-product/.docs/introduction.md ================================================ # Introduction You work for a government agency that has intercepted a series of encrypted communication signals from a group of bank robbers. The signals contain a long sequence of digits. Your team needs to use various digital signal processing techniques to analyze the signals and identify any patterns that may indicate the planning of a heist. ================================================ FILE: exercises/practice/largest-series-product/.meta/config.json ================================================ { "authors": [ "geoand" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/LargestSeriesProduct.kt" ], "test": [ "src/test/kotlin/SeriesTest.kt" ], "example": [ ".meta/src/reference/kotlin/LargestSeriesProduct.kt" ] }, "blurb": "Given a string of digits, calculate the largest product for a contiguous substring of digits of length n.", "source": "A variation on Problem 8 at Project Euler", "source_url": "https://projecteuler.net/problem=8" } ================================================ FILE: exercises/practice/largest-series-product/.meta/src/reference/kotlin/LargestSeriesProduct.kt ================================================ import java.lang.Math.max class Series(private val digits: String) { init { require(digits.all { it.isDigit() }) } fun getLargestProduct(span: Int): Long { require(span >= 0) require(digits.length >= span) if(digits.isEmpty()) { return 1 } return calculateRec(digits.map { it.intValue() }, span, 0) } private tailrec fun calculateRec(digits: List, span: Int, maxSoFar: Long): Long { val currentProduct = digits.subList(0, span).prod() val newMax = kotlin.math.max(currentProduct, maxSoFar) if(digits.size == span) { //since we won't be checking 'remainders' of the list, the end condition is simply when the size is the same as the span return newMax } return calculateRec(digits.tail(), span, newMax) } } fun Char.intValue() : Int { if(!this.isDigit()) { throw IllegalArgumentException("Char ${this} is not a legal DEC character") } return this.intDiff('0') } fun Char.intDiff(other: Char) = this.code - other.code fun List.prod() : Long = this.fold(1L) {productSoFar, item -> item*productSoFar} fun List.tail() = this.subList(1, this.size) ================================================ FILE: exercises/practice/largest-series-product/.meta/tests.toml ================================================ [canonical-tests] # finds the largest product if span equals length "7c82f8b7-e347-48ee-8a22-f672323324d4" = true # can find the largest product of 2 with numbers in order "88523f65-21ba-4458-a76a-b4aaf6e4cb5e" = true # can find the largest product of 2 "f1376b48-1157-419d-92c2-1d7e36a70b8a" = true # can find the largest product of 3 with numbers in order "46356a67-7e02-489e-8fea-321c2fa7b4a4" = true # can find the largest product of 3 "a2dcb54b-2b8f-4993-92dd-5ce56dece64a" = true # can find the largest product of 5 with numbers in order "673210a3-33cd-4708-940b-c482d7a88f9d" = true # can get the largest product of a big number "02acd5a6-3bbf-46df-8282-8b313a80a7c9" = true # reports zero if the only digits are zero "76dcc407-21e9-424c-a98e-609f269622b5" = true # reports zero if all spans include zero "6ef0df9f-52d4-4a5d-b210-f6fae5f20e19" = true # rejects span longer than string length "5d81aaf7-4f67-4125-bf33-11493cc7eab7" = true # reports 1 for empty string and empty product (0 span) "06bc8b90-0c51-4c54-ac22-3ec3893a079e" = true # reports 1 for nonempty string and empty product (0 span) "3ec0d92e-f2e2-4090-a380-70afee02f4c0" = true # rejects empty string and nonzero span "6d96c691-4374-4404-80ee-2ea8f3613dd4" = true # rejects invalid character in digits "7a38f2d6-3c35-45f6-8d6f-12e6e32d4d74" = true # rejects negative span "5fe3c0e5-a945-49f2-b584-f0814b4dd1ef" = true ================================================ FILE: exercises/practice/largest-series-product/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/largest-series-product/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/largest-series-product/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/largest-series-product/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/largest-series-product/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/largest-series-product/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/largest-series-product/src/main/kotlin/LargestSeriesProduct.kt ================================================ class Series { // TODO: Implement proper constructor fun getLargestProduct(span: Int): Long { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/largest-series-product/src/test/kotlin/SeriesTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class SeriesTest { @Test fun `corner - span equals length`() = assertLSPEquals("29", 2, 18) @Ignore @Test fun `numbers in order - span 2`() = assertLSPEquals("0123456789", 2, 72) @Ignore @Test fun `span 2`() = assertLSPEquals("576802143", 2, 48) @Ignore @Test fun `numbers in order - span 3`() = assertLSPEquals("0123456789", 3, 504) @Ignore @Test fun `span 3`() = assertLSPEquals("1027839564", 3, 270) @Ignore @Test fun `numbers in order - span 5`() = assertLSPEquals("0123456789", 5, 15120) @Ignore @Test fun `corner - long source sequence`() = assertLSPEquals("73167176531330624919225119674426574742355349194934", 6, 23520) @Ignore @Test fun `zeros - only`() = assertLSPEquals("0000", 2, 0) @Ignore @Test fun `zeros - dense`() = assertLSPEquals("99099", 3, 0) @Ignore @Test(expected = IllegalArgumentException::class) fun `reject - span longer than string length`() { lsp("123", 4) } @Ignore @Test(expected = IllegalArgumentException::class) fun `reject - empty string and nonzero span`() { lsp("", 1) } @Ignore @Test(expected = IllegalArgumentException::class) fun `reject - nondigits in source sequence`() { Series("1234a5") } @Ignore @Test(expected = IllegalArgumentException::class) fun `reject - negative span`() { lsp("12345", -1) } } private fun assertLSPEquals(input: String, span: Int, lsp: Long) { assertEquals(lsp(input, span), lsp) } private fun lsp(input: String, span: Int) = Series(input).getLargestProduct(span) ================================================ FILE: exercises/practice/leap/.approaches/boolean-chain/content.md ================================================ # Chain of Boolean expressions ```kotlin data class Year(val year: Int) { val isLeap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) } ``` The first boolean expression uses the [modulus operator][modulus-operator] to check if the year is evenly divided by `4`. - If the year is not evenly divisible by `4`, then the chain will "short circuit" due to the next operator being a [logical AND][logical-and] (`&&`), and will return `false`. - If the year _is_ evenly divisible by `4`, then the year is checked to _not_ be evenly divisible by `100`. - If the year is not evenly divisible by `100`, then the expression is `true` and the chain will "short-circuit" to return `true`, since the next operator is a [logical OR][logical-or] (`||`). - If the year _is_ evenly divisible by `100`, then the expression is `false`, and the returned value from the chain will be if the year is evenly divisible by `400`. | year | year % 4 == 0 | year % 100 != 0 | year % 400 == 0 | is leap year | | ---- | ------------- | --------------- | --------------- | ------------ | | 2020 | true | true | not evaluated | true | | 2019 | false | not evaluated | not evaluated | false | | 2000 | true | false | true | true | | 1900 | true | false | false | false | The chain of boolean expressions is efficient, as it proceeds from testing the most likely to least likely conditions. [modulus-operator]: https://www.programiz.com/kotlin-programming/operators [logical-and]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/and.html [logical-or]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/or.html ================================================ FILE: exercises/practice/leap/.approaches/boolean-chain/snippet.txt ================================================ data class Year(val year: Int) { val isLeap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) } ================================================ FILE: exercises/practice/leap/.approaches/built-in-method/content.md ================================================ # `isLeap()` ```kotlin import java.time.* data class Year(val year: Int) { val isLeap = LocalDate.of(year, Month.FEBRUARY, 28).isLeapYear } ``` This may be considered a "wicked cheat" for this exercise, by simply passing the year into the [isLeap()][is-leap] method of the [Year][year] class. Although it is not in the spirit of this exercise, `isLeap()` would be the idiomatic way to determine if a year is a leap year in the "real world". [is-leap]: https://docs.oracle.com/javase/8/docs/api/java/time/Year.html#isLeap-- [year]: https://docs.oracle.com/javase/8/docs/api/java/time/Year.html ================================================ FILE: exercises/practice/leap/.approaches/built-in-method/snippet.txt ================================================ import java.time.* data class Year(val year: Int) { val isLeap = LocalDate.of(year, Month.FEBRUARY, 28).isLeapYear } ================================================ FILE: exercises/practice/leap/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "21da8b43-0a72-4991-bfce-c2bc4a51d26b", "slug": "boolean-chain", "title": "Boolean chain", "blurb": "Use a chain of boolean expressions.", "authors": [ "bobahop" ] }, { "uuid": "03485733-b2e8-4be0-8a70-4a2d38ec2541", "slug": "ternary-expression", "title": "Ternary expression", "blurb": "Use a ternary expression.", "authors": [ "bobahop" ] }, { "uuid": "a5e8b72c-4061-4aa9-b8f1-0c4e0b577f94", "slug": "plusdays", "title": "plusDays method", "blurb": "Use the plusDays method.", "authors": [ "bobahop" ] }, { "uuid": "16c4ab8a-ae22-43db-911d-e8ee33b98cd8", "slug": "built-in-method", "title": "Built-in method", "blurb": "Use the built-in method.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/leap/.approaches/introduction.md ================================================ # Introduction There are various idiomatic approaches to solve Leap. You can use a chain of boolean expressions to test the conditions. Or you can use a [ternary expressions][ternary-expressions]. ## General guidance The key to solving Leap is to know if the year is evenly divisible by `4`, `100` and `400`. For determining that, you will use the [modulus operator][modulus-operator]. ## Approach: Chain of Boolean expressions ```kotlin data class Year(val year: Int) { val isLeap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) } ``` For more information, check the [Boolean chain approach][approach-boolean-chain]. ## Approach: Ternary expression ```kotlin data class Year(val year: Int) { val isLeap = if (year % 100 == 0) year % 400 == 0 else year % 4 == 0 } ``` For more information, check the [Ternary expression approach][approach-ternary-expression]. ## Other approaches Besides the aforementioned, idiomatic approaches, you could also approach the exercise as follows: ## `plusDays()` approach: Add a day to February 28th for the year and see if the new day is the 29th. For more information, see the [`plusDays()` approach][approach-plusdays]. ## Built-in method approach: Use the built-in method for the [Year][year]. For more information, see the [`isLeap()` approach][approach-isleap]. ## Which approach to use? - The chain of boolean expressions is most efficient, as it proceeds from the most likely to least likely conditions. It has a maximum of three checks. - The ternary expression has a maximum of only two checks, but it starts from a less likely condition. - Using `plusDays()` or using the built-in `isLeap()` method may be considered "cheats" for the exercise, but `isLeap()` would be the idiomatic way to check if a year is a leap year in Kotlin. [modulus-operator]: https://www.programiz.com/kotlin-programming/operators [ternary-expression]: https://kotlinlang.org/docs/control-flow.html#if-expression [approach-boolean-chain]: https://exercism.org/tracks/kotlin/exercises/leap/approaches/boolean-chain [approach-ternary-expression]: https://exercism.org/tracks/kotlin/exercises/leap/approaches/ternary-expression [approach-plusdays]: https://exercism.org/tracks/kotlin/exercises/leap/approaches/plusdays [year]: https://docs.oracle.com/javase/8/docs/api/java/time/Year.html [approach-isleap]: https://exercism.org/tracks/kotlin/exercises/leap/approaches/built-in-method ================================================ FILE: exercises/practice/leap/.approaches/plusdays/content.md ================================================ # `plusDays()` method ```kotlin import java.time.* data class Year(val year: Int) { val isLeap = LocalDate.of(year, Month.FEBRUARY, 28).plusDays(1).dayOfMonth == 29 } ``` This approach may be considered a "cheat" for this exercise. By adding a day to February 28th for the year, you can see if the new day is the 29th or the 1st. If it is the 29th, then the year is a leap year. This is done by using the [`plusDays()`][plusdays] and [`getDayOfMonth()`][getdayofmonth] methods of the [LocalDate][localdate] class. [plusdays]: https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/time/LocalDate.html#plusDays(long) [getdayofmonth]: https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/time/LocalDate.html#getDayOfMonth() [localdate]: https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/time/LocalDate.html ================================================ FILE: exercises/practice/leap/.approaches/plusdays/snippet.txt ================================================ import java.time.* data class Year(val year: Int) { val isLeap = LocalDate.of(year, Month.FEBRUARY, 28).plusDays(1).dayOfMonth == 29 } ================================================ FILE: exercises/practice/leap/.approaches/ternary-expression/content.md ================================================ Ternary expression ```kotlin data class Year(val year: Int) { val isLeap = if (year % 100 == 0) year % 400 == 0 else year % 4 == 0 } ``` A [ternary expression][ternary-expression] uses a maximum of two checks to determine if a year is a leap year. It starts by testing the outlier condition of the year being evenly divisible by `100`. It does this by using the [modulus operator][modulus-operator]. If the year is evenly divisible by `100`, then the expression is `true`, and the ternary expression returns if the year is evenly divisible by `400`. If the year is _not_ evenly divisible by `100`, then the expression is `false`, and the ternary expression returns if the year is evenly divisible by `4`. | year | year % 100 == 0 | year % 400 == 0 | year % 4 == 0 | is leap year | | ---- | --------------- | --------------- | -------------- | ------------ | | 2020 | false | not evaluated | true | true | | 2019 | false | not evaluated | false | false | | 2000 | true | true | not evaluated | true | | 1900 | true | false | not evaluated | false | Although it uses a maximum of only two checks, the ternary expression tests an outlier condition first, making it less efficient than another approach that would first test if the year is evenly divisible by `4`, which is more likely than the year being evenly divisible by `100`. [modulus-operator]: https://www.programiz.com/kotlin-programming/operators [ternary-expression]: https://kotlinlang.org/docs/control-flow.html#if-expression ================================================ FILE: exercises/practice/leap/.approaches/ternary-expression/snippet.txt ================================================ data class Year(val year: Int) { val isLeap = if (year % 100 == 0) year % 400 == 0 else year % 4 == 0 } ================================================ FILE: exercises/practice/leap/.docs/instructions.md ================================================ # Instructions Your task is to determine whether a given year is a leap year. ================================================ FILE: exercises/practice/leap/.docs/introduction.md ================================================ # Introduction A leap year (in the Gregorian calendar) occurs: - In every year that is evenly divisible by 4. - Unless the year is evenly divisible by 100, in which case it's only a leap year if the year is also evenly divisible by 400. Some examples: - 1997 was not a leap year as it's not divisible by 4. - 1900 was not a leap year as it's not divisible by 400. - 2000 was a leap year! ~~~~exercism/note For a delightful, four-minute explanation of the whole phenomenon of leap years, check out [this YouTube video](https://www.youtube.com/watch?v=xX96xng7sAE). ~~~~ ================================================ FILE: exercises/practice/leap/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Leap.kt" ], "test": [ "src/test/kotlin/LeapTest.kt" ], "example": [ ".meta/src/reference/kotlin/Leap.kt" ] }, "blurb": "Determine whether a given year is a leap year.", "source": "CodeRanch Cattle Drive, Assignment 3", "source_url": "https://web.archive.org/web/20240907033714/https://coderanch.com/t/718816/Leap" } ================================================ FILE: exercises/practice/leap/.meta/src/reference/kotlin/Leap.kt ================================================ data class Year(private val year: Int) { val isLeap: Boolean by lazy { divisibleBy(4) && (divisibleBy(400) || !divisibleBy(100)) } private fun divisibleBy(i: Int) = year % i == 0 } ================================================ FILE: exercises/practice/leap/.meta/tests.toml ================================================ [canonical-tests] # year not divisible by 4 in common year "6466b30d-519c-438e-935d-388224ab5223" = true # year divisible by 2, not divisible by 4 in common year "ac227e82-ee82-4a09-9eb6-4f84331ffdb0" = true # year divisible by 4, not divisible by 100 in leap year "4fe9b84c-8e65-489e-970b-856d60b8b78e" = true # year divisible by 4 and 5 is still a leap year "7fc6aed7-e63c-48f5-ae05-5fe182f60a5d" = true # year divisible by 100, not divisible by 400 in common year "78a7848f-9667-4192-ae53-87b30c9a02dd" = true # year divisible by 100 but not by 3 is still not a leap year "9d70f938-537c-40a6-ba19-f50739ce8bac" = true # year divisible by 400 in leap year "42ee56ad-d3e6-48f1-8e3f-c84078d916fc" = true # year divisible by 400 but not by 125 is still a leap year "57902c77-6fe9-40de-8302-587b5c27121e" = true # year divisible by 200, not divisible by 400 in common year "c30331f6-f9f6-4881-ad38-8ca8c12520c1" = true ================================================ FILE: exercises/practice/leap/.meta/version ================================================ 1.6.0 ================================================ FILE: exercises/practice/leap/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/leap/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/leap/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/leap/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/leap/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/leap/src/main/kotlin/Leap.kt ================================================ data class Year(val todo: Nothing) { // TODO: Implement proper constructor val isLeap: Boolean = TODO("Implement this getter to complete the task") } ================================================ FILE: exercises/practice/leap/src/test/kotlin/LeapTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertFalse import kotlin.test.assertTrue class LeapTest { @Test fun `not leap - not divisible by 4`() = assertYearIsCommon(2015) @Ignore @Test fun `not leap - divisible by 2, not divisible by 4`() = assertYearIsCommon(1970) @Ignore @Test fun `leap - divisible by 4, not divisible by 100`() = assertYearIsLeap(1996) @Ignore @Test fun `leap - divisible by 4 and 5`() = assertYearIsLeap(1960) @Ignore @Test fun `not leap - divisible by 100, not divisible by 400`() = assertYearIsCommon(2100) @Ignore @Test fun `not leap - divisible by 100 but not by 3`() = assertYearIsCommon(1900) @Ignore @Test fun `leap - divisible by 400`() = assertYearIsLeap(2000) @Ignore @Test fun `leap - divisible by 400 but not by 125`() = assertYearIsLeap(2400) @Ignore @Test fun `not leap - divisible by 200, not divisible by 400`() = assertYearIsCommon(1800) } private fun assertYearIsLeap(year: Int) = assertTrue(Year(year).isLeap) private fun assertYearIsCommon(year: Int) = assertFalse(Year(year).isLeap) ================================================ FILE: exercises/practice/linked-list/.docs/instructions.md ================================================ # Instructions Your team has decided to use a doubly linked list to represent each train route in the schedule. Each station along the train's route will be represented by a node in the linked list. You don't need to worry about arrival and departure times at the stations. Each station will simply be represented by a number. Routes can be extended, adding stations to the beginning or end of a route. They can also be shortened by removing stations from the beginning or the end of a route. Sometimes a station gets closed down, and in that case the station needs to be removed from the route, even if it is not at the beginning or end of the route. The size of a route is measured not by how far the train travels, but by how many stations it stops at. ~~~~exercism/note The linked list is a fundamental data structure in computer science, often used in the implementation of other data structures. As the name suggests, it is a list of nodes that are linked together. It is a list of "nodes", where each node links to its neighbor or neighbors. In a **singly linked list** each node links only to the node that follows it. In a **doubly linked list** each node links to both the node that comes before, as well as the node that comes after. If you want to dig deeper into linked lists, check out [this article][intro-linked-list] that explains it using nice drawings. [intro-linked-list]: https://medium.com/basecs/whats-a-linked-list-anyway-part-1-d8b7e6508b9d ~~~~ ================================================ FILE: exercises/practice/linked-list/.docs/introduction.md ================================================ # Introduction You are working on a project to develop a train scheduling system for a busy railway network. You've been asked to develop a prototype for the train routes in the scheduling system. Each route consists of a sequence of train stations that a given train stops at. ================================================ FILE: exercises/practice/linked-list/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/LinkedList.kt" ], "test": [ "src/test/kotlin/DequeTest.kt" ], "example": [ ".meta/src/reference/kotlin/LinkedList.kt" ] }, "blurb": "Implement a doubly linked list.", "source": "Classic computer science topic" } ================================================ FILE: exercises/practice/linked-list/.meta/src/reference/kotlin/LinkedList.kt ================================================ class Deque { private var head: Element? = null fun push(value: T) { if(head == null) { head = Element(value) head?.prev = head head?.next = head } else { val oldTail = head?.prev val tail = Element(value, prev = oldTail, next = head) oldTail?.next = tail head?.prev = tail } } fun pop(): T? { head = head?.prev return shift() } fun unshift(value: T) { push(value) head = head?.prev } fun shift(): T? { val value = head?.value val newHead = head?.next val newTail = head?.prev if (newHead == head) { head = null } else { newHead?.prev = newTail newTail?.next = newHead head = newHead } return value } private data class Element(val value: T, var prev: Element? = null, var next: Element? = null) } ================================================ FILE: exercises/practice/linked-list/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/linked-list/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/linked-list/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/linked-list/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/linked-list/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/linked-list/src/main/kotlin/LinkedList.kt ================================================ class Deque { fun push(value: T) { TODO("Implement this function to complete the task") } fun pop(): T? { TODO("Implement this function to complete the task") } fun unshift(value: T) { TODO("Implement this function to complete the task") } fun shift(): T? { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/linked-list/src/test/kotlin/DequeTest.kt ================================================ import org.junit.Before import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class DequeTest { private lateinit var subject: Deque @Before fun setUp() { subject = Deque() } @Test fun pushPop() { subject.push(10) subject.push(20) assertEquals(20, subject.pop()) assertEquals(10, subject.pop()) } @Ignore @Test fun pushShift() { subject.push(10) subject.push(20) assertEquals(10, subject.shift()) assertEquals(20, subject.shift()) } @Ignore @Test fun unshiftShift() { subject.unshift(10) subject.unshift(20) assertEquals(20, subject.shift()) assertEquals(10, subject.shift()) } @Ignore @Test fun unshiftPop() { subject.unshift(10) subject.unshift(20) assertEquals(10, subject.pop()) assertEquals(20, subject.pop()) } @Ignore @Test fun example() { subject.push(10) subject.push(20) assertEquals(20, subject.pop()) subject.push(30) assertEquals(10, subject.shift()) subject.unshift(40) subject.push(50) assertEquals(40, subject.shift()) assertEquals(50, subject.pop()) assertEquals(30, subject.shift()) } } ================================================ FILE: exercises/practice/list-ops/.docs/instructions.append.md ================================================ # Hints The tests for this exercise require you to use extensions, a mechanism for adding new functionality to an existing class whose source you do not directly control without having to subclass it. To learn more about Kotlin's implementations of extensions, check out the [official documentation](https://kotlinlang.org/docs/reference/extensions.html#extensions). The `customFoldLeft` and `customFoldRight` methods are "fold" functions, which is a concept well-known in the functional programming world, but less so in the object-oriented one. If you'd like more background information, check out this [fold](https://en.wikipedia.org/wiki/Fold_(higher-order_function)) page. ================================================ FILE: exercises/practice/list-ops/.docs/instructions.md ================================================ # Instructions Implement basic list operations. In functional languages list operations like `length`, `map`, and `reduce` are very common. Implement a series of basic list operations, without using existing functions. The precise number and names of the operations to be implemented will be track dependent to avoid conflicts with existing names, but the general operations you will implement include: - `append` (_given two lists, add all items in the second list to the end of the first list_); - `concatenate` (_given a series of lists, combine all items in all lists into one flattened list_); - `filter` (_given a predicate and a list, return the list of all items for which `predicate(item)` is True_); - `length` (_given a list, return the total number of items within it_); - `map` (_given a function and a list, return the list of the results of applying `function(item)` on all items_); - `foldl` (_given a function, a list, and initial accumulator, fold (reduce) each item into the accumulator from the left_); - `foldr` (_given a function, a list, and an initial accumulator, fold (reduce) each item into the accumulator from the right_); - `reverse` (_given a list, return a list with all the original items, but in reversed order_). Note, the ordering in which arguments are passed to the fold functions (`foldl`, `foldr`) is significant. ================================================ FILE: exercises/practice/list-ops/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "beatbrot", "dector", "eparovyshnaya", "lihofm", "mdowds", "myronmarston", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ListOps.kt" ], "test": [ "src/test/kotlin/ListExtensionsTest.kt" ], "example": [ ".meta/src/reference/kotlin/ListOps.kt" ] }, "blurb": "Implement basic list operations." } ================================================ FILE: exercises/practice/list-ops/.meta/src/reference/kotlin/ListOps.kt ================================================ fun List.customAppend(list: List): List { val result = mutableListOf() result.addAll(this) result.addAll(list) return result } fun List.customConcat(): List { val result = mutableListOf() forEach { result.add(it) } fun flatten(list: List): List = list.flatMap { if (it is List) flatten(it) else listOf(it) }.filterNotNull() return flatten(result) } fun List.customFilter(predicate: (T) -> Boolean): List { val result = mutableListOf() forEach { if (predicate(it)) { result.add(it) } } return result } val List.customSize: Int get() = size fun List.customMap(transform: (T) -> U): List { val result = mutableListOf() forEach { result.add(transform(it)) } return result } fun List.customFoldLeft(initial: U, f: (U, T) -> U): U { if (isEmpty()) return initial return drop(1).customFoldLeft(f(initial, first()), f) } fun List.customFoldRight(initial: U, f: (T, U) -> U): U { if (isEmpty()) return initial return f(first(), drop(1).customFoldRight(initial, f)) } fun List.customReverse(): List { val result = mutableListOf() forEach { result.add(0, it) } return result } ================================================ FILE: exercises/practice/list-ops/.meta/tests.toml ================================================ [canonical-tests] # empty lists "485b9452-bf94-40f7-a3db-c3cf4850066a" = true # list to empty list "2c894696-b609-4569-b149-8672134d340a" = true # non-empty lists "71dcf5eb-73ae-4a0e-b744-a52ee387922f" = true # empty list "28444355-201b-4af2-a2f6-5550227bde21" = true # list of lists "331451c1-9573-42a1-9869-2d06e3b389a9" = true # list of nested lists "d6ecd72c-197f-40c3-89a4-aa1f45827e09" = true # empty list "0524fba8-3e0f-4531-ad2b-f7a43da86a16" = true # non-empty list "88494bd5-f520-4edb-8631-88e415b62d24" = true # empty list "1cf0b92d-8d96-41d5-9c21-7b3c37cb6aad" = true # non-empty list "d7b8d2d9-2d16-44c4-9a19-6e5f237cb71e" = true # empty list "c0bc8962-30e2-4bec-9ae4-668b8ecd75aa" = true # non-empty list "11e71a95-e78b-4909-b8e4-60cdcaec0e91" = true # empty list "613b20b7-1873-4070-a3a6-70ae5f50d7cc" = true # direction independent function applied to non-empty list "e56df3eb-9405-416a-b13a-aabb4c3b5194" = true # direction dependent function applied to non-empty list "d2cf5644-aee1-4dfc-9b88-06896676fe27" = true # empty list "aeb576b9-118e-4a57-a451-db49fac20fdc" = true # direction independent function applied to non-empty list "c4b64e58-313e-4c47-9c68-7764964efb8e" = true # direction dependent function applied to non-empty list "be396a53-c074-4db3-8dd6-f7ed003cce7c" = true # empty list "94231515-050e-4841-943d-d4488ab4ee30" = true # non-empty list "fcc03d1e-42e0-4712-b689-d54ad761f360" = true # list of lists is not flattened "40872990-b5b8-4cb8-9085-d91fc0d05d26" = true ================================================ FILE: exercises/practice/list-ops/.meta/version ================================================ 2.4.1 ================================================ FILE: exercises/practice/list-ops/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/list-ops/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/list-ops/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/list-ops/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/list-ops/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/list-ops/src/main/kotlin/ListOps.kt ================================================ fun List.customAppend(list: List): List { TODO("Implement this function to complete the task") } fun List.customConcat(): List { TODO("Implement this function to complete the task") } fun List.customFilter(predicate: (T) -> Boolean): List { TODO("Implement this function to complete the task") } val List.customSize: Int get() = TODO("Implement this getter to complete the task") fun List.customMap(transform: (T) -> U): List { TODO("Implement this function to complete the task") } fun List.customFoldLeft(initial: U, f: (U, T) -> U): U { TODO("Implement this function to complete the task") } fun List.customFoldRight(initial: U, f: (T, U) -> U): U { TODO("Implement this function to complete the task") } fun List.customReverse(): List { TODO("Implement this function to complete the task") } ================================================ FILE: exercises/practice/list-ops/src/test/kotlin/ListExtensionsTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class ListExtensionsTest { @Test fun `append - empty lists`() = assertEquals( emptyList(), emptyList().customAppend(emptyList()) ) @Ignore @Test fun `append - list to empty list`() = assertEquals( listOf('1', '2', '3', '4'), emptyList().customAppend(listOf('1', '2', '3', '4')) ) @Ignore @Test fun `append - non-empty lists`() = assertEquals( listOf("1", "2", "2", "3", "4", "5"), listOf("1", "2").customAppend(listOf("2", "3", "4", "5")) ) @Ignore @Test fun `concatenate - empty list`() = assertEquals( emptyList(), emptyList().customConcat() ) @Ignore @Test fun `concatenate - list of lists`() = assertEquals( listOf('1', '2', '3', '4', '5', '6'), listOf( listOf('1', '2'), listOf('3'), emptyList(), listOf('4', '5', '6') ).customConcat() ) @Ignore @Test fun `concatenate - list of nested lists`() = assertEquals( listOf('1', '2', '3', '4', '5', '6'), listOf( listOf( listOf('1'), listOf('2') ), listOf( listOf('3') ), listOf( emptyList() ), listOf( listOf('4', '5', '6') ) ).customConcat() ) @Ignore @Test fun `filter - empty list`() = assertEquals( emptyList(), emptyList().customFilter { it % 2 == 1 }) @Ignore @Test fun `filter - non-empty list`() = assertEquals( listOf(1, 3, 5), listOf(1, 2, 3, 5).customFilter { it % 2 == 1 }) @Ignore @Test fun `size - empty list`() = assertEquals(0, emptyList().customSize) @Ignore @Test fun `size - non-empty list`() = assertEquals(4, listOf("one", "two", "three", "four").customSize) @Ignore @Test fun `map - empty list`() = assertEquals( emptyList(), emptyList().customMap { it -> it + 1 }) @Ignore @Test fun `map - non-empty list`() = assertEquals( listOf(2, 4, 6, 8), listOf(1, 3, 5, 7).customMap { it -> it + 1 }) @Ignore @Test fun `fold left - empty list`() = assertEquals( 2.0, emptyList().customFoldLeft(2.0, Double::times) ) @Ignore @Test fun `fold left - direction independent function`() = assertEquals( 15, listOf(1, 2, 3, 4).customFoldLeft(5, Int::plus) ) @Ignore @Test fun `fold left - direction dependent function`() = assertEquals( 0, listOf(2, 5).customFoldLeft(5, Int::div) ) @Ignore @Test fun `fold right - empty list`() = assertEquals( 2.0, emptyList().customFoldRight(2.0, Double::times) ) @Ignore @Test fun `fold right - direction independent function`() = assertEquals( 15, listOf(1, 2, 3, 4).customFoldRight(5, Int::plus) ) @Ignore @Test fun `fold right - direction dependent function`() = assertEquals( 2, listOf(2, 5).customFoldRight(5, Int::div) ) @Ignore @Test fun `reverse - empty list`() = assertEquals( emptyList(), emptyList().customReverse() ) @Ignore @Test fun `reverse - non-empty list`() = assertEquals( listOf('7', '5', '3', '1'), listOf('1', '3', '5', '7').customReverse() ) @Ignore @Test fun `reverse - list of lists`() = assertEquals( listOf( listOf('4', '5', '6'), emptyList(), '3', listOf('1', '2') ), listOf( listOf('1', '2'), '3', emptyList(), listOf('4', '5', '6') ).customReverse() ) } ================================================ FILE: exercises/practice/luhn/.docs/instructions.md ================================================ # Instructions Determine whether a credit card number is valid according to the [Luhn formula][luhn]. The number will be provided as a string. ## Validating a number Strings of length 1 or less are not valid. Spaces are allowed in the input, but they should be stripped before checking. All other non-digit characters are disallowed. ### Example 1: valid credit card number ```text 4539 3195 0343 6467 ``` The first step of the Luhn algorithm is to double every second digit, starting from the right. We will be doubling ```text 4539 3195 0343 6467 ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ (double these) ``` If doubling the number results in a number greater than 9 then subtract 9 from the product. The results of our doubling: ```text 8569 6195 0383 3437 ``` Then sum all of the digits: ```text 8+5+6+9+6+1+9+5+0+3+8+3+3+4+3+7 = 80 ``` If the sum is evenly divisible by 10, then the number is valid. This number is valid! ### Example 2: invalid credit card number ```text 8273 1232 7352 0569 ``` Double the second digits, starting from the right ```text 7253 2262 5312 0539 ``` Sum the digits ```text 7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57 ``` 57 is not evenly divisible by 10, so this number is not valid. [luhn]: https://en.wikipedia.org/wiki/Luhn_algorithm ================================================ FILE: exercises/practice/luhn/.docs/introduction.md ================================================ # Introduction At the Global Verification Authority, you've just been entrusted with a critical assignment. Across the city, from online purchases to secure logins, countless operations rely on the accuracy of numerical identifiers like credit card numbers, bank account numbers, transaction codes, and tracking IDs. The Luhn algorithm is a simple checksum formula used to ensure these numbers are valid and error-free. A batch of identifiers has just arrived on your desk. All of them must pass the Luhn test to ensure they're legitimate. If any fail, they'll be flagged as invalid, preventing errors or fraud, such as incorrect transactions or unauthorized access. Can you ensure this is done right? The integrity of many services depends on you. ================================================ FILE: exercises/practice/luhn/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "enixander", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Luhn.kt" ], "test": [ "src/test/kotlin/LuhnTest.kt" ], "example": [ ".meta/src/reference/kotlin/Luhn.kt" ] }, "blurb": "Given a number determine whether or not it is valid per the Luhn formula.", "source": "The Luhn Algorithm on Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Luhn_algorithm" } ================================================ FILE: exercises/practice/luhn/.meta/src/reference/kotlin/Luhn.kt ================================================ object Luhn { fun isValid(candidate: String): Boolean = isValidCandidate(candidate) && checksum(number(candidate)) == 0 private fun isValidCandidate(candidate: String): Boolean = candidate.filter(Char::isDigit).length > 1 && candidate.all { it.isDigit() || Character.isSpaceChar(it) } private fun number(candidate: String) = candidate.filter(Char::isDigit).toLong() private fun checksum(number: Long) = addends(number).sum() % 10 private fun addends(number: Long): List = digits(number).withIndex().reversed() .map { if (isOdd(it.index)) dbl(it.value) else it.value } private fun digits(n: Long): List = when (n) { 0L -> emptyList() else -> listOf((n % 10).toInt()) + digits(n / 10) } private fun dbl(n: Int): Int { val dbled = n * 2 return if (dbled > 9) dbled - 9 else dbled } private fun isOdd(i: Int) = i % 2 == 1 } ================================================ FILE: exercises/practice/luhn/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [792a7082-feb7-48c7-b88b-bbfec160865e] description = "single digit strings can not be valid" [698a7924-64d4-4d89-8daa-32e1aadc271e] description = "a single zero is invalid" [73c2f62b-9b10-4c9f-9a04-83cee7367965] description = "a simple valid SIN that remains valid if reversed" [9369092e-b095-439f-948d-498bd076be11] description = "a simple valid SIN that becomes invalid if reversed" [8f9f2350-1faf-4008-ba84-85cbb93ffeca] description = "a valid Canadian SIN" [1cdcf269-6560-44fc-91f6-5819a7548737] description = "invalid Canadian SIN" [656c48c1-34e8-4e60-9a5a-aad8a367810a] description = "invalid credit card" [20e67fad-2121-43ed-99a8-14b5b856adb9] description = "invalid long number with an even remainder" [ad2a0c5f-84ed-4e5b-95da-6011d6f4f0aa] description = "valid number with an even number of digits" [ef081c06-a41f-4761-8492-385e13c8202d] description = "valid number with an odd number of spaces" [bef66f64-6100-4cbb-8f94-4c9713c5e5b2] description = "valid strings with a non-digit added at the end become invalid" [2177e225-9ce7-40f6-b55d-fa420e62938e] description = "valid strings with punctuation included become invalid" [ebf04f27-9698-45e1-9afe-7e0851d0fe8d] description = "valid strings with symbols included become invalid" [08195c5e-ce7f-422c-a5eb-3e45fece68ba] description = "single zero with space is invalid" [12e63a3c-f866-4a79-8c14-b359fc386091] description = "more than a single zero is valid" [ab56fa80-5de8-4735-8a4a-14dae588663e] description = "input digit 9 is correctly converted to output digit 9" [8a7c0e24-85ea-4154-9cf1-c2db90eabc08] description = "valid luhn with an odd number of digits and non zero first digit" [39a06a5a-5bad-4e0f-b215-b042d46209b1] description = "using ascii value for non-doubled non-digit isn't allowed" [f94cf191-a62f-4868-bc72-7253114aa157] description = "using ascii value for doubled non-digit isn't allowed" ================================================ FILE: exercises/practice/luhn/.meta/version ================================================ 1.6.1 ================================================ FILE: exercises/practice/luhn/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/luhn/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/luhn/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/luhn/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/luhn/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/luhn/src/main/kotlin/Luhn.kt ================================================ object Luhn { fun isValid(candidate: String): Boolean { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/luhn/src/test/kotlin/LuhnTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertFalse import kotlin.test.assertTrue class LuhnTest { @Test fun `invalid - single digit`() = assertInvalid("1") @Ignore @Test fun `invalid - a single zero`() = assertInvalid("0") @Ignore @Test fun `valid - simple reversable`() = assertValid("059") @Ignore @Test fun `valid - simple unreversable`() = assertValid("59") @Ignore @Test fun `valid - Canadian`() = assertValid("055 444 285") @Ignore @Test fun `invalid - Canadian`() = assertInvalid("055 444 286") @Ignore @Test fun `invalid - credit card`() = assertInvalid("8273 1232 7352 0569") @Ignore @Test fun `valid - even amount of digits`() = assertValid("095 245 88") @Ignore @Test fun `valid - odd amount of spaces`() = assertValid("234 567 891 234") @Ignore @Test fun `invalid - non-digit at the end of valid`() = assertInvalid("059a") @Ignore @Test fun `invalid - punctuation in valid`() = assertInvalid("055-444-285") @Ignore @Test fun `invalid - symbols in valid`() = assertInvalid("055# 444$ 285") @Ignore @Test fun `invalid - single zero with space`() = assertInvalid(" 0") @Ignore @Test fun `valid - many zeros`() = assertValid("0000 0") @Ignore @Test fun `valid - input digit 9`() = assertValid("091") @Ignore @Test fun `valid | valid luhn with an odd number of digits and non zero first digit`() = assertValid("109") /** * Convert non-digits to their ascii values and then offset them by 48 * sometimes accidentally declare an invalid string to be valid. * This test is designed to avoid that solution. */ @Ignore @Test fun `invalid - ascii value for non-doubled non-digit in the middle`() = assertInvalid("055b 444 285") /** * Convert non-digits to their ascii values and then offset them by 48 * sometimes accidentally declare an invalid string to be valid. * This test is designed to avoid that solution. */ @Ignore @Test fun `invalid - ascii value for non-doubled non-digit at the start`() = assertInvalid(":9") } private fun assertValid(value: String) = assertTrue(Luhn.isValid(value)) private fun assertInvalid(value: String) = assertFalse(Luhn.isValid(value)) ================================================ FILE: exercises/practice/matching-brackets/.docs/instructions.md ================================================ # Instructions Given a string containing brackets `[]`, braces `{}`, parentheses `()`, or any combination thereof, verify that any and all pairs are matched and nested correctly. Any other characters should be ignored. For example, `"{what is (42)}?"` is balanced and `"[text}"` is not. ================================================ FILE: exercises/practice/matching-brackets/.docs/introduction.md ================================================ # Introduction You're given the opportunity to write software for the Bracketeer™, an ancient but powerful mainframe. The software that runs on it is written in a proprietary language. Much of its syntax is familiar, but you notice _lots_ of brackets, braces and parentheses. Despite the Bracketeer™ being powerful, it lacks flexibility. If the source code has any unbalanced brackets, braces or parentheses, the Bracketeer™ crashes and must be rebooted. To avoid such a scenario, you start writing code that can verify that brackets, braces, and parentheses are balanced before attempting to run it on the Bracketeer™. ================================================ FILE: exercises/practice/matching-brackets/.meta/config.json ================================================ { "authors": [ "geoand" ], "contributors": [ "dector", "enixander", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/MatchingBrackets.kt" ], "test": [ "src/test/kotlin/MatchingBracketsTest.kt" ], "example": [ ".meta/src/reference/kotlin/MatchingBrackets.kt" ] }, "blurb": "Make sure the brackets and braces all match.", "source": "Ginna Baker" } ================================================ FILE: exercises/practice/matching-brackets/.meta/src/reference/kotlin/MatchingBrackets.kt ================================================ import java.util.* import java.util.Collections.asLifoQueue object MatchingBrackets { private val CLOSING_TO_OPENING_MAP = mapOf( '}' to '{', ')' to '(', ']' to '[' ) private val OPENING_BRACKETS = CLOSING_TO_OPENING_MAP.values private val CLOSING_BRACKETS = CLOSING_TO_OPENING_MAP.keys private val ALL_BRACKET = OPENING_BRACKETS + CLOSING_BRACKETS fun isValid(input: String): Boolean { val onlyBracketChars = input.filter { it.isBracket() }.toList() return isValidRec(onlyBracketChars, asLifoQueue(ArrayDeque())) } private tailrec fun isValidRec(bracketChars: List, stack: Queue): Boolean { if(bracketChars.isEmpty()) { return stack.isEmpty() } val firstChar = bracketChars.first() if(firstChar.isOpeningBracket()) { return isValidRec(bracketChars.tail(), stack.push(firstChar)) } else { val stackHead = stack.poll() ?: return false val isMatch = firstChar.matchingOpeningBracket() == stackHead return if(isMatch) isValidRec(bracketChars.tail(), stack) else false } } fun Char.isBracket() = this in ALL_BRACKET fun Char.isOpeningBracket() = this in OPENING_BRACKETS fun Char.matchingOpeningBracket() = CLOSING_TO_OPENING_MAP[this] ?: throw IllegalArgumentException("Char ${this} is not a closing bracket") } fun List.tail() = this.subList(1, this.size) fun Queue.push(element: T): Queue { this.add(element) return this } ================================================ FILE: exercises/practice/matching-brackets/.meta/tests.toml ================================================ [canonical-tests] # paired square brackets "81ec11da-38dd-442a-bcf9-3de7754609a5" = true # empty string "287f0167-ac60-4b64-8452-a0aa8f4e5238" = true # unpaired brackets "6c3615a3-df01-4130-a731-8ef5f5d78dac" = true # wrong ordered brackets "9d414171-9b98-4cac-a4e5-941039a97a77" = true # wrong closing bracket "f0f97c94-a149-4736-bc61-f2c5148ffb85" = true # paired with whitespace "754468e0-4696-4582-a30e-534d47d69756" = true # partially paired brackets "ba84f6ee-8164-434a-9c3e-b02c7f8e8545" = true # simple nested brackets "3c86c897-5ff3-4a2b-ad9b-47ac3a30651d" = true # several paired brackets "2d137f2c-a19e-4993-9830-83967a2d4726" = true # paired and nested brackets "2e1f7b56-c137-4c92-9781-958638885a44" = true # unopened closing brackets "84f6233b-e0f7-4077-8966-8085d295c19b" = true # unpaired and nested brackets "9b18c67d-7595-4982-b2c5-4cb949745d49" = true # paired and wrong nested brackets "a0205e34-c2ac-49e6-a88a-899508d7d68e" = true # paired and incomplete brackets "ef47c21b-bcfd-4998-844c-7ad5daad90a8" = true # too many closing brackets "a4675a40-a8be-4fc2-bc47-2a282ce6edbe" = true # math expression "99255f93-261b-4435-a352-02bdecc9bdf2" = true # complex latex expression "8e357d79-f302-469a-8515-2561877256a1" = true ================================================ FILE: exercises/practice/matching-brackets/.meta/version ================================================ 2.0.0 ================================================ FILE: exercises/practice/matching-brackets/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/matching-brackets/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/matching-brackets/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/matching-brackets/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/matching-brackets/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/matching-brackets/src/main/kotlin/MatchingBrackets.kt ================================================ object MatchingBrackets { fun isValid(input: String): Boolean { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/matching-brackets/src/test/kotlin/MatchingBracketsTest.kt ================================================ import org.junit.Test import org.junit.Ignore import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals @RunWith(Parameterized::class) class MatchingBracketsTest(val input: String, val expectedOutput: Boolean) { companion object { @JvmStatic @Parameterized.Parameters(name = "{index}: bracket({0})={1}") fun data() = listOf( arrayOf("[]", true), arrayOf("", true), arrayOf("[[", false), arrayOf("}{", false), arrayOf("{]", false), arrayOf("{ }", true), arrayOf("{[])", false), arrayOf("{[]}", true), arrayOf("{}[]", true), arrayOf("([{}({}[])])", true), arrayOf("{[)][]}", false), arrayOf("([{])", false), arrayOf("[({]})", false), arrayOf("{}[", false), arrayOf("[]]", false), arrayOf("(((185 + 223.85) * 15) - 543)/2", true), arrayOf("\\\\left(\\\\begin{array}{cc} \\\\frac{1}{3} & x\\\\\\\\ \\\\mathrm{e}^{x} &... x^2 \\\\end{array}\\\\right)", true) ) } @Test fun test() { assertEquals(expectedOutput, MatchingBrackets.isValid(input)) } } ================================================ FILE: exercises/practice/matrix/.docs/instructions.md ================================================ # Instructions Given a string representing a matrix of numbers, return the rows and columns of that matrix. So given a string with embedded newlines like: ```text 9 8 7 5 3 2 6 6 7 ``` representing this matrix: ```text 1 2 3 |--------- 1 | 9 8 7 2 | 5 3 2 3 | 6 6 7 ``` your code should be able to spit out: - A list of the rows, reading each row left-to-right while moving top-to-bottom across the rows, - A list of the columns, reading each column top-to-bottom while moving from left-to-right. The rows for our example matrix: - 9, 8, 7 - 5, 3, 2 - 6, 6, 7 And its columns: - 9, 5, 6 - 8, 3, 6 - 7, 2, 7 ================================================ FILE: exercises/practice/matrix/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "SunCatMC", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Matrix.kt" ], "test": [ "src/test/kotlin/MatrixTest.kt" ], "example": [ ".meta/src/reference/kotlin/Matrix.kt" ] }, "blurb": "Given a string representing a matrix of numbers, return the rows and columns of that matrix.", "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", "source_url": "https://turing.edu" } ================================================ FILE: exercises/practice/matrix/.meta/src/reference/kotlin/Matrix.kt ================================================ class Matrix(private val matrixAsString: String) { private val matrix: List> = matrixAsString .split("\n") .map { column -> column.trim().split(Regex(" +")) .map { cell -> cell.toInt() } } fun column(colNr: Int): List = matrix.indices.map { matrix[it][colNr - 1] } fun row(rowNr: Int): List = matrix[rowNr - 1] } ================================================ FILE: exercises/practice/matrix/.meta/tests.toml ================================================ [canonical-tests] # extract row from one number matrix "ca733dab-9d85-4065-9ef6-a880a951dafd" = true # can extract row "5c93ec93-80e1-4268-9fc2-63bc7d23385c" = true # extract row where numbers have different widths "2f1aad89-ad0f-4bd2-9919-99a8bff0305a" = true # can extract row from non-square matrix with no corresponding column "68f7f6ba-57e2-4e87-82d0-ad09889b5204" = true # extract column from one number matrix "e8c74391-c93b-4aed-8bfe-f3c9beb89ebb" = true # can extract column "7136bdbd-b3dc-48c4-a10c-8230976d3727" = true # can extract column from non-square matrix with no corresponding row "ad64f8d7-bba6-4182-8adf-0c14de3d0eca" = true # extract column where numbers have different widths "9eddfa5c-8474-440e-ae0a-f018c2a0dd89" = true ================================================ FILE: exercises/practice/matrix/.meta/version ================================================ 1.3.0 ================================================ FILE: exercises/practice/matrix/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/matrix/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/matrix/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/matrix/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/matrix/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/matrix/src/main/kotlin/Matrix.kt ================================================ class Matrix(private val matrixAsString: String) { fun column(colNr: Int): List { TODO("Implement this to complete the task") } fun row(rowNr: Int): List { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/matrix/src/test/kotlin/MatrixTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class MatrixTest { @Test fun `extract row from one number matrix`() { val matrixAsString = "1" val rowIndex = 1 val expectedRow = listOf(1) assertEquals(expectedRow, Matrix(matrixAsString).row(rowIndex)) } @Ignore @Test fun `extract row from matrix`() { val matrixAsString = "1 2\n3 4" val rowIndex = 2 val expectedRow = listOf(3, 4) assertEquals(expectedRow, Matrix(matrixAsString).row(rowIndex)) } @Ignore @Test fun `extract row from diff widths matrix`() { val matrixAsString = "1 2\n10 20" val rowIndex = 2 val expectedRow = listOf(10, 20) assertEquals(expectedRow, Matrix(matrixAsString).row(rowIndex)) } @Ignore @Test fun `extract row from non square matrix`() { val matrixAsString = """ 1 2 3 4 5 6 7 8 9 8 7 6 """.trimIndent() val rowIndex = 4 val expectedRow = listOf(8, 7, 6) assertEquals(expectedRow, Matrix(matrixAsString).row(rowIndex)) } @Ignore @Test fun `extract column from one number matrix`() { val matrixAsString = "1" val columnIndex = 1 val expectedColumn = listOf(1) assertEquals(expectedColumn, Matrix(matrixAsString).column(columnIndex)) } @Ignore @Test fun `extract column matrix`() { val matrixAsString = """ 1 2 3 4 5 6 7 8 9 """.trimIndent() val columnIndex = 3 val expectedColumn = listOf(3, 6, 9) assertEquals(expectedColumn, Matrix(matrixAsString).column(columnIndex)) } @Ignore @Test fun `extract column from non square matrix`() { val matrixAsString = """ 1 2 3 4 5 6 7 8 9 8 7 6 """.trimIndent() val columnIndex = 4 val expectedColumn = listOf(4, 8, 6) assertEquals(expectedColumn, Matrix(matrixAsString).column(columnIndex)) } @Ignore @Test fun `extract column from diff widths matrix`() { val matrixAsString = """ 89 1903 3 18 3 1 9 4 800 """.replace(Regex(" +"), " ").trimIndent() val columnIndex = 2 val expectedColumn = listOf(1903, 3, 4) assertEquals(expectedColumn, Matrix(matrixAsString).column(columnIndex)) } } ================================================ FILE: exercises/practice/meetup/.docs/instructions.md ================================================ # Instructions Your task is to find the exact date of a meetup, given a month, year, weekday and week. There are five week values to consider: `first`, `second`, `third`, `fourth`, `last`, `teenth`. For example, you might be asked to find the date for the meetup on the first Monday in January 2018 (January 1, 2018). Similarly, you might be asked to find: - the third Tuesday of August 2019 (August 20, 2019) - the teenth Wednesday of May 2020 (May 13, 2020) - the fourth Sunday of July 2021 (July 25, 2021) - the last Thursday of November 2022 (November 24, 2022) - the teenth Saturday of August 1953 (August 15, 1953) ## Teenth The teenth week refers to the seven days in a month that end in '-teenth' (13th, 14th, 15th, 16th, 17th, 18th and 19th). If asked to find the teenth Saturday of August, 1953, we check its calendar: ```plaintext August 1953 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ``` From this we find that the teenth Saturday is August 15, 1953. ================================================ FILE: exercises/practice/meetup/.docs/introduction.md ================================================ # Introduction Every month, your partner meets up with their best friend. Both of them have very busy schedules, making it challenging to find a suitable date! Given your own busy schedule, your partner always double-checks potential meetup dates with you: - "Can I meet up on the first Friday of next month?" - "What about the third Wednesday?" - "Maybe the last Sunday?" In this month's call, your partner asked you this question: - "I'd like to meet up on the teenth Thursday; is that okay?" Confused, you ask what a "teenth" day is. Your partner explains that a teenth day, a concept they made up, refers to the days in a month that end in '-teenth': - 13th (thirteenth) - 14th (fourteenth) - 15th (fifteenth) - 16th (sixteenth) - 17th (seventeenth) - 18th (eighteenth) - 19th (nineteenth) As there are also seven weekdays, it is guaranteed that each day of the week has _exactly one_ teenth day each month. Now that you understand the concept of a teenth day, you check your calendar. You don't have anything planned on the teenth Thursday, so you happily confirm the date with your partner. ================================================ FILE: exercises/practice/meetup/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Meetup.kt" ], "test": [ "src/test/kotlin/MeetupTest.kt" ], "example": [ ".meta/src/reference/kotlin/Meetup.kt" ] }, "blurb": "Calculate the date of meetups.", "source": "Jeremy Hinegardner mentioned a Boulder meetup that happens on the Wednesteenth of every month" } ================================================ FILE: exercises/practice/meetup/.meta/src/reference/kotlin/Meetup.kt ================================================ import java.time.DayOfWeek import java.time.LocalDate class Meetup(monthOfYear: Int, year: Int) { private val startOfMonth: LocalDate = LocalDate.of(year, monthOfYear, 1) fun day(dayOfWeek: DayOfWeek, schedule: MeetupSchedule): LocalDate { var result = cycleToNext(dayOfWeek, startOfMonth) @Suppress("NON_EXHAUSTIVE_WHEN") when (schedule) { MeetupSchedule.SECOND -> result = result.plusWeeks(1) MeetupSchedule.THIRD -> result = result.plusWeeks(2) MeetupSchedule.FOURTH -> result = result.plusWeeks(3) MeetupSchedule.LAST -> result = cycleToPrev(dayOfWeek, startOfMonth.plusMonths(1).minusDays(1)) MeetupSchedule.TEENTH -> { while (result.dayOfMonth < 13) result = result.plusWeeks(1) } // TODO: This may need to be fixed in the future as Kotlin 1.7+ may raise a compilation error for // non-exhaustive when blocks. } return result } private fun cycleToPrev(dayOfWeek: DayOfWeek, current: LocalDate): LocalDate { var result = current while (result.dayOfWeek != dayOfWeek) { result = result.minusDays(1) } return result } private fun cycleToNext(dayOfWeek: DayOfWeek, current: LocalDate): LocalDate { var result = current while (result.dayOfWeek != dayOfWeek) { result = result.plusDays(1) } return result } } ================================================ FILE: exercises/practice/meetup/.meta/src/reference/kotlin/MeetupSchedule.kt ================================================ enum class MeetupSchedule { FIRST, SECOND, THIRD, FOURTH, LAST, TEENTH } ================================================ FILE: exercises/practice/meetup/.meta/tests.toml ================================================ [canonical-tests] # monteenth of May 2013 "d7f8eadd-d4fc-46ee-8a20-e97bd3fd01c8" = true # monteenth of August 2013 "f78373d1-cd53-4a7f-9d37-e15bf8a456b4" = true # monteenth of September 2013 "8c78bea7-a116-425b-9c6b-c9898266d92a" = true # tuesteenth of March 2013 "cfef881b-9dc9-4d0b-8de4-82d0f39fc271" = true # tuesteenth of April 2013 "69048961-3b00-41f9-97ee-eb6d83a8e92b" = true # tuesteenth of August 2013 "d30bade8-3622-466a-b7be-587414e0caa6" = true # wednesteenth of January 2013 "8db4b58b-92f3-4687-867b-82ee1a04f851" = true # wednesteenth of February 2013 "6c27a2a2-28f8-487f-ae81-35d08c4664f7" = true # wednesteenth of June 2013 "008a8674-1958-45b5-b8e6-c2c9960d973a" = true # thursteenth of May 2013 "e4abd5e3-57cb-4091-8420-d97e955c0dbd" = true # thursteenth of June 2013 "85da0b0f-eace-4297-a6dd-63588d5055b4" = true # thursteenth of September 2013 "ecf64f9b-8413-489b-bf6e-128045f70bcc" = true # friteenth of April 2013 "ac4e180c-7d0a-4d3d-b05f-f564ebb584ca" = true # friteenth of August 2013 "b79101c7-83ad-4f8f-8ec8-591683296315" = true # friteenth of September 2013 "6ed38b9f-0072-4901-bd97-7c8b8b0ef1b8" = true # saturteenth of February 2013 "dfae03ed-9610-47de-a632-655ab01e1e7c" = true # saturteenth of April 2013 "ec02e3e1-fc72-4a3c-872f-a53fa8ab358e" = true # saturteenth of October 2013 "d983094b-7259-4195-b84e-5d09578c89d9" = true # sunteenth of May 2013 "d84a2a2e-f745-443a-9368-30051be60c2e" = true # sunteenth of June 2013 "0e64bc53-92a3-4f61-85b2-0b7168c7ce5a" = true # sunteenth of October 2013 "de87652c-185e-4854-b3ae-04cf6150eead" = true # first Monday of March 2013 "2cbfd0f5-ba3a-46da-a8cc-0fe4966d3411" = true # first Monday of April 2013 "a6168c7c-ed95-4bb3-8f92-c72575fc64b0" = true # first Tuesday of May 2013 "1bfc620f-1c54-4bbd-931f-4a1cd1036c20" = true # first Tuesday of June 2013 "12959c10-7362-4ca0-a048-50cf1c06e3e2" = true # first Wednesday of July 2013 "1033dc66-8d0b-48a1-90cb-270703d59d1d" = true # first Wednesday of August 2013 "b89185b9-2f32-46f4-a602-de20b09058f6" = true # first Thursday of September 2013 "53aedc4d-b2c8-4dfb-abf7-a8dc9cdceed5" = true # first Thursday of October 2013 "b420a7e3-a94c-4226-870a-9eb3a92647f0" = true # first Friday of November 2013 "61df3270-28b4-4713-bee2-566fa27302ca" = true # first Friday of December 2013 "cad33d4d-595c-412f-85cf-3874c6e07abf" = true # first Saturday of January 2013 "a2869b52-5bba-44f0-a863-07bd1f67eadb" = true # first Saturday of February 2013 "3585315a-d0db-4ea1-822e-0f22e2a645f5" = true # first Sunday of March 2013 "c49e9bd9-8ccf-4cf2-947a-0ccd4e4f10b1" = true # first Sunday of April 2013 "1513328b-df53-4714-8677-df68c4f9366c" = true # second Monday of March 2013 "49e083af-47ec-4018-b807-62ef411efed7" = true # second Monday of April 2013 "6cb79a73-38fe-4475-9101-9eec36cf79e5" = true # second Tuesday of May 2013 "4c39b594-af7e-4445-aa03-bf4f8effd9a1" = true # second Tuesday of June 2013 "41b32c34-2e39-40e3-b790-93539aaeb6dd" = true # second Wednesday of July 2013 "90a160c5-b5d9-4831-927f-63a78b17843d" = true # second Wednesday of August 2013 "23b98ce7-8dd5-41a1-9310-ef27209741cb" = true # second Thursday of September 2013 "447f1960-27ca-4729-bc3f-f36043f43ed0" = true # second Thursday of October 2013 "c9aa2687-300c-4e79-86ca-077849a81bde" = true # second Friday of November 2013 "a7e11ef3-6625-4134-acda-3e7195421c09" = true # second Friday of December 2013 "8b420e5f-9290-4106-b5ae-022f3e2a3e41" = true # second Saturday of January 2013 "80631afc-fc11-4546-8b5f-c12aaeb72b4f" = true # second Saturday of February 2013 "e34d43ac-f470-44c2-aa5f-e97b78ecaf83" = true # second Sunday of March 2013 "a57d59fd-1023-47ad-b0df-a6feb21b44fc" = true # second Sunday of April 2013 "a829a8b0-abdd-4ad1-b66c-5560d843c91a" = true # third Monday of March 2013 "501a8a77-6038-4fc0-b74c-33634906c29d" = true # third Monday of April 2013 "49e4516e-cf32-4a58-8bbc-494b7e851c92" = true # third Tuesday of May 2013 "4db61095-f7c7-493c-85f1-9996ad3012c7" = true # third Tuesday of June 2013 "714fc2e3-58d0-4b91-90fd-61eefd2892c0" = true # third Wednesday of July 2013 "b08a051a-2c80-445b-9b0e-524171a166d1" = true # third Wednesday of August 2013 "80bb9eff-3905-4c61-8dc9-bb03016d8ff8" = true # third Thursday of September 2013 "fa52a299-f77f-4784-b290-ba9189fbd9c9" = true # third Thursday of October 2013 "f74b1bc6-cc5c-4bf1-ba69-c554a969eb38" = true # third Friday of November 2013 "8900f3b0-801a-466b-a866-f42d64667abd" = true # third Friday of December 2013 "538ac405-a091-4314-9ccd-920c4e38e85e" = true # third Saturday of January 2013 "244db35c-2716-4fa0-88ce-afd58e5cf910" = true # third Saturday of February 2013 "dd28544f-f8fa-4f06-9bcd-0ad46ce68e9e" = true # third Sunday of March 2013 "be71dcc6-00d2-4b53-a369-cbfae55b312f" = true # third Sunday of April 2013 "b7d2da84-4290-4ee6-a618-ee124ae78be7" = true # fourth Monday of March 2013 "4276dc06-a1bd-4fc2-b6c2-625fee90bc88" = true # fourth Monday of April 2013 "ddbd7976-2deb-4250-8a38-925ac1a8e9a2" = true # fourth Tuesday of May 2013 "eb714ef4-1656-47cc-913c-844dba4ebddd" = true # fourth Tuesday of June 2013 "16648435-7937-4d2d-b118-c3e38fd084bd" = true # fourth Wednesday of July 2013 "de062bdc-9484-437a-a8c5-5253c6f6785a" = true # fourth Wednesday of August 2013 "c2ce6821-169c-4832-8d37-690ef5d9514a" = true # fourth Thursday of September 2013 "d462c631-2894-4391-a8e3-dbb98b7a7303" = true # fourth Thursday of October 2013 "9ff1f7b6-1b72-427d-9ee9-82b5bb08b835" = true # fourth Friday of November 2013 "83bae8ba-1c49-49bc-b632-b7c7e1d7e35f" = true # fourth Friday of December 2013 "de752d2a-a95e-48d2-835b-93363dac3710" = true # fourth Saturday of January 2013 "eedd90ad-d581-45db-8312-4c6dcf9cf560" = true # fourth Saturday of February 2013 "669fedcd-912e-48c7-a0a1-228b34af91d0" = true # fourth Sunday of March 2013 "648e3849-ea49-44a5-a8a3-9f2a43b3bf1b" = true # fourth Sunday of April 2013 "f81321b3-99ab-4db6-9267-69c5da5a7823" = true # last Monday of March 2013 "1af5e51f-5488-4548-aee8-11d7d4a730dc" = true # last Monday of April 2013 "f29999f2-235e-4ec7-9dab-26f137146526" = true # last Tuesday of May 2013 "31b097a0-508e-48ac-bf8a-f63cdcf6dc41" = true # last Tuesday of June 2013 "8c022150-0bb5-4a1f-80f9-88b2e2abcba4" = true # last Wednesday of July 2013 "0e762194-672a-4bdf-8a37-1e59fdacef12" = true # last Wednesday of August 2013 "5016386a-f24e-4bd7-b439-95358f491b66" = true # last Thursday of September 2013 "12ead1a5-cdf9-4192-9a56-2229e93dd149" = true # last Thursday of October 2013 "7db89e11-7fbe-4e57-ae3c-0f327fbd7cc7" = true # last Friday of November 2013 "e47a739e-b979-460d-9c8a-75c35ca2290b" = true # last Friday of December 2013 "5bed5aa9-a57a-4e5d-8997-2cc796a5b0ec" = true # last Saturday of January 2013 "61e54cba-76f3-4772-a2b1-bf443fda2137" = true # last Saturday of February 2013 "8b6a737b-2fa9-444c-b1a2-80ce7a2ec72f" = true # last Sunday of March 2013 "0b63e682-f429-4d19-9809-4a45bd0242dc" = true # last Sunday of April 2013 "5232307e-d3e3-4afc-8ba6-4084ad987c00" = true # last Wednesday of February 2012 "0bbd48e8-9773-4e81-8e71-b9a51711e3c5" = true # last Wednesday of December 2014 "fe0936de-7eee-4a48-88dd-66c07ab1fefc" = true # last Sunday of February 2015 "2ccf2488-aafc-4671-a24e-2b6effe1b0e2" = true # first Friday of December 2012 "00c3ce9f-cf36-4b70-90d8-92b32be6830e" = true ================================================ FILE: exercises/practice/meetup/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/meetup/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/meetup/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/meetup/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/meetup/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/meetup/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/meetup/src/main/kotlin/Meetup.kt ================================================ import java.time.DayOfWeek import java.time.LocalDate class Meetup { // TODO: implement proper constructor fun day(dayOfWeek: DayOfWeek, schedule: MeetupSchedule): LocalDate{ TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/meetup/src/main/kotlin/MeetupSchedule.kt ================================================ enum class MeetupSchedule { FIRST, SECOND, THIRD, FOURTH, LAST, TEENTH } ================================================ FILE: exercises/practice/meetup/src/test/kotlin/MeetupTest.kt ================================================ import org.junit.Ignore import org.junit.Test import java.time.DayOfWeek import java.time.LocalDate import kotlin.test.assertEquals class MeetupTest { @Test fun testMonteenthOfMay2013() { val expected = LocalDate.of(2013, 5, 13) val meetup = Meetup(5, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testMonteenthOfAugust2013() { val expected = LocalDate.of(2013, 8, 19) val meetup = Meetup(8, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testMonteenthOfSeptember2013() { val expected = LocalDate.of(2013, 9, 16) val meetup = Meetup(9, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testTuesteenthOfMarch2013() { val expected = LocalDate.of(2013, 3, 19) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testTuesteenthOfApril2013() { val expected = LocalDate.of(2013, 4, 16) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testTuesteenthOfAugust2013() { val expected = LocalDate.of(2013, 8, 13) val meetup = Meetup(8, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testWednesteenthOfJanuary2013() { val expected = LocalDate.of(2013, 1, 16) val meetup = Meetup(1, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testWednesteenthOfFebruary2013() { val expected = LocalDate.of(2013, 2, 13) val meetup = Meetup(2, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testWednesteenthOfJune2013() { val expected = LocalDate.of(2013, 6, 19) val meetup = Meetup(6, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testThursteenthOfMay2013() { val expected = LocalDate.of(2013, 5, 16) val meetup = Meetup(5, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testThursteenthOfJune2013() { val expected = LocalDate.of(2013, 6, 13) val meetup = Meetup(6, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testThursteenthOfSeptember2013() { val expected = LocalDate.of(2013, 9, 19) val meetup = Meetup(9, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testFriteenthOfApril2013() { val expected = LocalDate.of(2013, 4, 19) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testFriteenthOfAugust2013() { val expected = LocalDate.of(2013, 8, 16) val meetup = Meetup(8, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testFriteenthOfSeptember2013() { val expected = LocalDate.of(2013, 9, 13) val meetup = Meetup(9, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testSaturteenthOfFebruary2013() { val expected = LocalDate.of(2013, 2, 16) val meetup = Meetup(2, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testSaturteenthOfApril2013() { val expected = LocalDate.of(2013, 4, 13) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testSaturteenthOfOctober2013() { val expected = LocalDate.of(2013, 10, 19) val meetup = Meetup(10, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testSunteenthOfMay2013() { val expected = LocalDate.of(2013, 5, 19) val meetup = Meetup(5, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testSunteenthOfJune2013() { val expected = LocalDate.of(2013, 6, 16) val meetup = Meetup(6, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testSunteenthOfOctober2013() { val expected = LocalDate.of(2013, 10, 13) val meetup = Meetup(10, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.TEENTH)) } @Ignore @Test fun testFirstMondayOfMarch2013() { val expected = LocalDate.of(2013, 3, 4) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstMondayOfApril2013() { val expected = LocalDate.of(2013, 4, 1) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstTuesdayOfMay2013() { val expected = LocalDate.of(2013, 5, 7) val meetup = Meetup(5, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstTuesdayOfJune2013() { val expected = LocalDate.of(2013, 6, 4) val meetup = Meetup(6, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstWednesdayOfJuly2013() { val expected = LocalDate.of(2013, 7, 3) val meetup = Meetup(7, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstWednesdayOfAugust2013() { val expected = LocalDate.of(2013, 8, 7) val meetup = Meetup(8, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstThursdayOfSeptember2013() { val expected = LocalDate.of(2013, 9, 5) val meetup = Meetup(9, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstThursdayOfOctober2013() { val expected = LocalDate.of(2013, 10, 3) val meetup = Meetup(10, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstFridayOfNovember2013() { val expected = LocalDate.of(2013, 11, 1) val meetup = Meetup(11, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstFridayOfDecember2013() { val expected = LocalDate.of(2013, 12, 6) val meetup = Meetup(12, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstSaturdayOfJanuary2013() { val expected = LocalDate.of(2013, 1, 5) val meetup = Meetup(1, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstSaturdayOfFebruary2013() { val expected = LocalDate.of(2013, 2, 2) val meetup = Meetup(2, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstSundayOfMarch2013() { val expected = LocalDate.of(2013, 3, 3) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testFirstSundayOfApril2013() { val expected = LocalDate.of(2013, 4, 7) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.FIRST)) } @Ignore @Test fun testSecondMondayOfMarch2013() { val expected = LocalDate.of(2013, 3, 11) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondMondayOfApril2013() { val expected = LocalDate.of(2013, 4, 8) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondTuesdayOfMay2013() { val expected = LocalDate.of(2013, 5, 14) val meetup = Meetup(5, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondTuesdayOfJune2013() { val expected = LocalDate.of(2013, 6, 11) val meetup = Meetup(6, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondWednesdayOfJuly2013() { val expected = LocalDate.of(2013, 7, 10) val meetup = Meetup(7, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondWednesdayOfAugust2013() { val expected = LocalDate.of(2013, 8, 14) val meetup = Meetup(8, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondThursdayOfSeptember2013() { val expected = LocalDate.of(2013, 9, 12) val meetup = Meetup(9, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondThursdayOfOctober2013() { val expected = LocalDate.of(2013, 10, 10) val meetup = Meetup(10, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondFridayOfNovember2013() { val expected = LocalDate.of(2013, 11, 8) val meetup = Meetup(11, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondFridayOfDecember2013() { val expected = LocalDate.of(2013, 12, 13) val meetup = Meetup(12, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondSaturdayOfJanuary2013() { val expected = LocalDate.of(2013, 1, 12) val meetup = Meetup(1, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondSaturdayOfFebruary2013() { val expected = LocalDate.of(2013, 2, 9) val meetup = Meetup(2, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondSundayOfMarch2013() { val expected = LocalDate.of(2013, 3, 10) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testSecondSundayOfApril2013() { val expected = LocalDate.of(2013, 4, 14) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.SECOND)) } @Ignore @Test fun testThirdMondayOfMarch2013() { val expected = LocalDate.of(2013, 3, 18) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdMondayOfApril2013() { val expected = LocalDate.of(2013, 4, 15) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdTuesdayOfMay2013() { val expected = LocalDate.of(2013, 5, 21) val meetup = Meetup(5, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdTuesdayOfJune2013() { val expected = LocalDate.of(2013, 6, 18) val meetup = Meetup(6, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdWednesdayOfJuly2013() { val expected = LocalDate.of(2013, 7, 17) val meetup = Meetup(7, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdWednesdayOfAugust2013() { val expected = LocalDate.of(2013, 8, 21) val meetup = Meetup(8, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdThursdayOfSeptember2013() { val expected = LocalDate.of(2013, 9, 19) val meetup = Meetup(9, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdThursdayOfOctober2013() { val expected = LocalDate.of(2013, 10, 17) val meetup = Meetup(10, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdFridayOfNovember2013() { val expected = LocalDate.of(2013, 11, 15) val meetup = Meetup(11, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdFridayOfDecember2013() { val expected = LocalDate.of(2013, 12, 20) val meetup = Meetup(12, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdSaturdayOfJanuary2013() { val expected = LocalDate.of(2013, 1, 19) val meetup = Meetup(1, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdSaturdayOfFebruary2013() { val expected = LocalDate.of(2013, 2, 16) val meetup = Meetup(2, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdSundayOfMarch2013() { val expected = LocalDate.of(2013, 3, 17) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testThirdSundayOfApril2013() { val expected = LocalDate.of(2013, 4, 21) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.THIRD)) } @Ignore @Test fun testFourthMondayOfMarch2013() { val expected = LocalDate.of(2013, 3, 25) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthMondayOfApril2013() { val expected = LocalDate.of(2013, 4, 22) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthTuesdayOfMay2013() { val expected = LocalDate.of(2013, 5, 28) val meetup = Meetup(5, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthTuesdayOfJune2013() { val expected = LocalDate.of(2013, 6, 25) val meetup = Meetup(6, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthWednesdayOfJuly2013() { val expected = LocalDate.of(2013, 7, 24) val meetup = Meetup(7, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthWednesdayOfAugust2013() { val expected = LocalDate.of(2013, 8, 28) val meetup = Meetup(8, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthThursdayOfSeptember2013() { val expected = LocalDate.of(2013, 9, 26) val meetup = Meetup(9, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthThursdayOfOctober2013() { val expected = LocalDate.of(2013, 10, 24) val meetup = Meetup(10, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthFridayOfNovember2013() { val expected = LocalDate.of(2013, 11, 22) val meetup = Meetup(11, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthFridayOfDecember2013() { val expected = LocalDate.of(2013, 12, 27) val meetup = Meetup(12, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthSaturdayOfJanuary2013() { val expected = LocalDate.of(2013, 1, 26) val meetup = Meetup(1, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthSaturdayOfFebruary2013() { val expected = LocalDate.of(2013, 2, 23) val meetup = Meetup(2, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthSundayOfMarch2013() { val expected = LocalDate.of(2013, 3, 24) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testFourthSundayOfApril2013() { val expected = LocalDate.of(2013, 4, 28) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.FOURTH)) } @Ignore @Test fun testLastMondayOfMarch2013() { val expected = LocalDate.of(2013, 3, 25) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastMondayOfApril2013() { val expected = LocalDate.of(2013, 4, 29) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.MONDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastTuesdayOfMay2013() { val expected = LocalDate.of(2013, 5, 28) val meetup = Meetup(5, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastTuesdayOfJune2013() { val expected = LocalDate.of(2013, 6, 25) val meetup = Meetup(6, 2013) assertEquals(expected, meetup.day(DayOfWeek.TUESDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastWednesdayOfJuly2013() { val expected = LocalDate.of(2013, 7, 31) val meetup = Meetup(7, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastWednesdayOfAugust2013() { val expected = LocalDate.of(2013, 8, 28) val meetup = Meetup(8, 2013) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastThursdayOfSeptember2013() { val expected = LocalDate.of(2013, 9, 26) val meetup = Meetup(9, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastThursdayOfOctober2013() { val expected = LocalDate.of(2013, 10, 31) val meetup = Meetup(10, 2013) assertEquals(expected, meetup.day(DayOfWeek.THURSDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastFridayOfNovember2013() { val expected = LocalDate.of(2013, 11, 29) val meetup = Meetup(11, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastFridayOfDecember2013() { val expected = LocalDate.of(2013, 12, 27) val meetup = Meetup(12, 2013) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastSaturdayOfJanuary2013() { val expected = LocalDate.of(2013, 1, 26) val meetup = Meetup(1, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastSaturdayOfFebruary2013() { val expected = LocalDate.of(2013, 2, 23) val meetup = Meetup(2, 2013) assertEquals(expected, meetup.day(DayOfWeek.SATURDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastSundayOfMarch2013() { val expected = LocalDate.of(2013, 3, 31) val meetup = Meetup(3, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastSundayOfApril2013() { val expected = LocalDate.of(2013, 4, 28) val meetup = Meetup(4, 2013) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastWednesdayOfFebruary2012() { val expected = LocalDate.of(2012, 2, 29) val meetup = Meetup(2, 2012) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastWednesdayOfDecember2014() { val expected = LocalDate.of(2014, 12, 31) val meetup = Meetup(12, 2014) assertEquals(expected, meetup.day(DayOfWeek.WEDNESDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testLastSundayOfFebruary2015() { val expected = LocalDate.of(2015, 2, 22) val meetup = Meetup(2, 2015) assertEquals(expected, meetup.day(DayOfWeek.SUNDAY, MeetupSchedule.LAST)) } @Ignore @Test fun testFirstFridayOfDecember2012() { val expected = LocalDate.of(2012, 12, 7) val meetup = Meetup(12, 2012) assertEquals(expected, meetup.day(DayOfWeek.FRIDAY, MeetupSchedule.FIRST)) } } ================================================ FILE: exercises/practice/minesweeper/.docs/instructions.md ================================================ # Instructions Your task is to add the mine counts to empty squares in a completed Minesweeper board. The board itself is a rectangle composed of squares that are either empty (`' '`) or a mine (`'*'`). For each empty square, count the number of mines adjacent to it (horizontally, vertically, diagonally). If the empty square has no adjacent mines, leave it empty. Otherwise replace it with the adjacent mines count. For example, you may receive a 5 x 4 board like this (empty spaces are represented here with the '·' character for display on screen): ```text ·*·*· ··*·· ··*·· ····· ``` Which your code should transform into this: ```text 1*3*1 13*31 ·2*2· ·111· ``` ================================================ FILE: exercises/practice/minesweeper/.docs/introduction.md ================================================ # Introduction [Minesweeper][wikipedia] is a popular game where the user has to find the mines using numeric hints that indicate how many mines are directly adjacent (horizontally, vertically, diagonally) to a square. [wikipedia]: https://en.wikipedia.org/wiki/Minesweeper_(video_game) ================================================ FILE: exercises/practice/minesweeper/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Minesweeper.kt" ], "test": [ "src/test/kotlin/MinesweeperBoardTest.kt" ], "example": [ ".meta/src/reference/kotlin/Minesweeper.kt" ] }, "blurb": "Add the numbers to a minesweeper board." } ================================================ FILE: exercises/practice/minesweeper/.meta/src/reference/kotlin/Minesweeper.kt ================================================ import kotlin.math.max import kotlin.math.min private const val MINE_CHAR = '*' private const val SPACE_CHAR = ' ' data class MinesweeperBoard(val mineLocations: List) { private val numberOfRows by lazy { mineLocations.size } private val numberOfColumns by lazy { if (mineLocations.isEmpty()) 0 else mineLocations[0].length } fun withNumbers() = (0 until numberOfRows).map { getRowWithNumbers(it) } private fun getRowWithNumbers(rowNumber: Int) = (0 until numberOfColumns) .map { columnNumber -> getCellNumber(rowNumber, columnNumber) } .joinToString("") private fun getCellNumber(rowNumber: Int, columnNumber: Int): Char { // If (rowNumber, columnNumber) is a mine, we're done. if (mineLocations[rowNumber][columnNumber] == MINE_CHAR) { return MINE_CHAR } val mineCount = computeMineCountAround(rowNumber, columnNumber) // If computed count is positive, add it to the annotated row. Otherwise, add a blank space. return if (mineCount > 0) Character.forDigit(mineCount, 10) else SPACE_CHAR } private fun computeMineCountAround(rowNumber: Int, columnNumber: Int): Int { var result = 0 // Compute row and column ranges to inspect (respecting board edges). val minRowToInspect = max(rowNumber - 1, 0) val maxRowToInspect = min(rowNumber + 1, numberOfRows - 1) val minColToInspect = max(columnNumber - 1, 0) val maxColToInspect = min(columnNumber + 1, numberOfColumns - 1) // Count mines in the cells surrounding (row, col). for (rowToInspect in minRowToInspect..maxRowToInspect) { for (colToInspect in minColToInspect..maxColToInspect) { if (mineLocations[rowToInspect][colToInspect] == MINE_CHAR) { result += 1 } } } return result } } ================================================ FILE: exercises/practice/minesweeper/.meta/tests.toml ================================================ [canonical-tests] # no rows "0c5ec4bd-dea7-4138-8651-1203e1cb9f44" = true # no columns "650ac4c0-ad6b-4b41-acde-e4ea5852c3b8" = true # no mines "6fbf8f6d-a03b-42c9-9a58-b489e9235478" = true # minefield with only mines "61aff1c4-fb31-4078-acad-cd5f1e635655" = true # mine surrounded by spaces "84167147-c504-4896-85d7-246b01dea7c5" = true # space surrounded by mines "cb878f35-43e3-4c9d-93d9-139012cccc4a" = true # horizontal line "7037f483-ddb4-4b35-b005-0d0f4ef4606f" = true # horizontal line, mines at edges "e359820f-bb8b-4eda-8762-47b64dba30a6" = true # vertical line "c5198b50-804f-47e9-ae02-c3b42f7ce3ab" = true # vertical line, mines at edges "0c79a64d-703d-4660-9e90-5adfa5408939" = true # cross "4b098563-b7f3-401c-97c6-79dd1b708f34" = true # large minefield "04a260f1-b40a-4e89-839e-8dd8525abe0e" = true ================================================ FILE: exercises/practice/minesweeper/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/minesweeper/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/minesweeper/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/minesweeper/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/minesweeper/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/minesweeper/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/minesweeper/src/main/kotlin/Minesweeper.kt ================================================ data class MinesweeperBoard(val todo: Nothing) { // TODO: Implement proper constructor fun withNumbers(): List { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/minesweeper/src/test/kotlin/MinesweeperBoardTest.kt ================================================ import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException import kotlin.test.assertEquals class MinesweeperBoardTest { /* * See https://github.com/junit-team/junit4/wiki/Rules for information on JUnit Rules in general and * ExpectedExceptions in particular. */ @Rule @JvmField var expectedException: ExpectedException = ExpectedException.none() @Test fun testInputBoardWithNoRowsAndNoColumns() { val inputBoard = emptyList() val expectedNumberedBoard = emptyList() val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithOneRowAndNoColumns() { val inputBoard = listOf("") val expectedNumberedBoard = listOf("") val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithNoMines() { val inputBoard = listOf( " ", " ", " " ) val expectedNumberedBoard = listOf( " ", " ", " " ) val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithOnlyMines() { val inputBoard = listOf( "***", "***", "***" ) val expectedNumberedBoard = listOf( "***", "***", "***" ) val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleMineAtCenter() { val inputBoard = listOf( " ", " * ", " " ) val expectedNumberedBoard = listOf( "111", "1*1", "111" ) val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithMinesAroundPerimeter() { val inputBoard = listOf( "***", "* *", "***" ) val expectedNumberedBoard = listOf( "***", "*8*", "***" ) val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleRowAndTwoMines() { val inputBoard = listOf(" * * ") val expectedNumberedBoard = listOf("1*2*1") val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleRowAndTwoMinesAtEdges() { val inputBoard = listOf("* *") val expectedNumberedBoard = listOf("*1 1*") val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleColumnAndTwoMines() { val inputBoard = listOf( " ", "*", " ", "*", " " ) val expectedNumberedBoard = listOf( "1", "*", "2", "*", "1" ) val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithSingleColumnAndTwoMinesAtEdges() { val inputBoard = listOf( "*", " ", " ", " ", "*" ) val expectedNumberedBoard = listOf( "*", "1", " ", "1", "*" ) val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testInputBoardWithMinesInCross() { val inputBoard = listOf( " * ", " * ", "*****", " * ", " * " ) val expectedNumberedBoard = listOf( " 2*2 ", "25*52", "*****", "25*52", " 2*2 " ) val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } @Ignore @Test fun testLargeInputBoard() { val inputBoard = listOf( " * * ", " * ", " * ", " * *", " * * ", " " ) val expectedNumberedBoard = listOf( "1*22*1", "12*322", " 123*2", "112*4*", "1*22*2", "111111" ) val actualNumberedBoard = MinesweeperBoard(inputBoard).withNumbers() assertEquals(expectedNumberedBoard, actualNumberedBoard) } } ================================================ FILE: exercises/practice/nth-prime/.docs/instructions.md ================================================ # Instructions Given a number n, determine what the nth prime is. By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. If your language provides methods in the standard library to deal with prime numbers, pretend they don't exist and implement them yourself. ================================================ FILE: exercises/practice/nth-prime/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/NthPrime.kt" ], "test": [ "src/test/kotlin/PrimeTest.kt" ], "example": [ ".meta/src/reference/kotlin/NthPrime.kt" ] }, "blurb": "Given a number n, determine what the nth prime is.", "source": "A variation on Problem 7 at Project Euler", "source_url": "https://projecteuler.net/problem=7" } ================================================ FILE: exercises/practice/nth-prime/.meta/src/reference/kotlin/NthPrime.kt ================================================ import java.math.BigInteger object Prime { fun nth(n: Int): Int { require(n > 0) { "There is no zeroth prime." } return primes().drop(n - 1).first().toInt() } private fun primes(): Sequence = generateSequence(BigInteger.valueOf(2)) { previous -> previous.nextProbablePrime() } } ================================================ FILE: exercises/practice/nth-prime/.meta/tests.toml ================================================ [canonical-tests] # first prime "75c65189-8aef-471a-81de-0a90c728160c" = true # second prime "2c38804c-295f-4701-b728-56dea34fd1a0" = true # sixth prime "56692534-781e-4e8c-b1f9-3e82c1640259" = true # big prime "fce1e979-0edb-412d-93aa-2c744e8f50ff" = true # there is no zeroth prime "bd0a9eae-6df7-485b-a144-80e13c7d55b2" = true ================================================ FILE: exercises/practice/nth-prime/.meta/version ================================================ 2.1.0 ================================================ FILE: exercises/practice/nth-prime/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/nth-prime/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/nth-prime/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/nth-prime/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/nth-prime/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/nth-prime/src/main/kotlin/NthPrime.kt ================================================ object Prime { fun nth(n: Int): Int { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/nth-prime/src/test/kotlin/PrimeTest.kt ================================================ import org.junit.Test import org.junit.Ignore import org.junit.Rule import org.junit.rules.ExpectedException import kotlin.test.assertEquals class PrimeTest { @Rule @JvmField var expectedException: ExpectedException = ExpectedException.none() @Test fun firstPrime() { assertEquals(2, Prime.nth(1)) } @Ignore @Test fun secondPrime() { assertEquals(3, Prime.nth(2)) } @Ignore @Test fun sixthPrime() { assertEquals(13, Prime.nth(6)) } @Ignore @Test fun bigPrime() { assertEquals(104743, Prime.nth(10001)) } @Ignore @Test fun undefinedPrime() { expectedException.expect(IllegalArgumentException::class.java) expectedException.expectMessage("There is no zeroth prime.") Prime.nth(0) } } ================================================ FILE: exercises/practice/nucleotide-count/.approaches/config.json ================================================ { "introduction": { "authors": [ "ErwinOlie" ] }, "approaches": [ { "uuid": "56375e89-328b-4fb6-9195-91fd8e623fd3", "slug": "groupby-plus", "title": "groupBy with +", "blurb": "Use groupBy to count the nucleotides and add them to the base case.", "authors": [ "ErwinOlie" ] } ] } ================================================ FILE: exercises/practice/nucleotide-count/.approaches/groupby-plus/content.md ================================================ # `groupBy` with `+` ```kotlin class Dna(val sequence: String) { init { require(sequence.all { it in "ACGT" }) } val nucleotideCounts get() = mapOf('A' to 0, 'C' to 0, 'G' to 0, 'T' to 0) + sequence.groupingBy { it }.eachCount() } ``` ## Verification We receive a sequence as input, which we have to verify. Because the sequence is part of the primary constructor, which can't contain runnable code, we have to place the check in an [_initializer block_][stdlib-constructors]. In Kotlin it's idiomatic to use the [`require`][stdlib-require] keyword for verification. `require` will throw an `IllegalArgumentException` if the given value is `false`. ```kotlin init { require(sequence.all { it in "ACGT" }) } ``` ## Base Map We define a base map with a zero value for every nucleotide. We do this to ensure that every nucleotide will be present in the output, even if there is no count. Afterward we can overwrite some of the values by using the `+` operator. Note that the [`+` operator on maps][map-plus] does not add the values but overwrites them. ```kotlin val nucleotideCounts get() = mapOf('A' to 0, 'C' to 0, 'G' to 0, 'T' to 0) ``` ## Counting Nucleotides We use the `.groupingBy` function to create a [`Grouping`][stdlib-grouping] of the nucleotides. By using the `.eachCount()` function we turn the [`Grouping`][stdlib-grouping] in a Map. For example: `"ACA".groupingBy { it }.eachCount()` results in `{A=2, C=1}`. After [adding][map-plus] the maps together we receive our final answer. ```kotlin val nucleotideCounts get() = mapOf('A' to 0, 'C' to 0, 'G' to 0, 'T' to 0) + sequence.groupingBy { it }.eachCount() ``` [stdlib-require]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/require.html [stdlib-constructors]: https://kotlinlang.org/docs/classes.html#constructors [stdlib-grouping]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-grouping/ [stdlib-eachcount]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/each-count.html [map-plus]: https://kotlinlang.org/docs/map-operations.html#plus-and-minus-operators ================================================ FILE: exercises/practice/nucleotide-count/.approaches/groupby-plus/snippet.txt ================================================ class Dna(val sequence: String) { init { require(sequence.all { it in "ACGT" }) } val nucleotideCounts get() = mapOf('A' to 0, 'C' to 0, 'G' to 0, 'T' to 0) + sequence.groupingBy { it }.eachCount() } ================================================ FILE: exercises/practice/nucleotide-count/.approaches/introduction.md ================================================ # Introduction Each solution has to contain the following three elements: - Check the input for any invalid characters. - Count the presence of every nucleotide. - Ensure that the missing nucleotides are also present in the output. ## Approach: `groupBy` with `+` One approach is to use `groupBy` and the `+` operator: ```kotlin class Dna(val sequence: String) { init { require(sequence.all { it in "ACGT" }) } val nucleotideCounts get() = mapOf('A' to 0, 'C' to 0, 'G' to 0, 'T' to 0) + sequence.groupingBy { it }.eachCount() } ``` For more information, check the [`groupBy` with `+` approach][approach-groupby-plus]. [approach-groupby-plus]: https://exercism.org/tracks/kotlin/exercises/nucleotide-count/approaches/groupby-plus ================================================ FILE: exercises/practice/nucleotide-count/.docs/instructions.md ================================================ # Instructions Each of us inherits from our biological parents a set of chemical instructions known as DNA that influence how our bodies are constructed. All known life depends on DNA! > Note: You do not need to understand anything about nucleotides or DNA to complete this exercise. DNA is a long chain of other chemicals and the most important are the four nucleotides, adenine, cytosine, guanine and thymine. A single DNA chain can contain billions of these four nucleotides and the order in which they occur is important! We call the order of these nucleotides in a bit of DNA a "DNA sequence". We represent a DNA sequence as an ordered collection of these four nucleotides and a common way to do that is with a string of characters such as "ATTACG" for a DNA sequence of 6 nucleotides. 'A' for adenine, 'C' for cytosine, 'G' for guanine, and 'T' for thymine. Given a string representing a DNA sequence, count how many of each nucleotide is present. If the string contains characters that aren't A, C, G, or T then it is invalid and you should signal an error. For example: ```text "GATTACA" -> 'A': 3, 'C': 1, 'G': 1, 'T': 2 "INVALID" -> error ``` ================================================ FILE: exercises/practice/nucleotide-count/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Dna.kt" ], "test": [ "src/test/kotlin/DnaTest.kt" ], "example": [ ".meta/src/reference/kotlin/Dna.kt" ] }, "blurb": "Given a DNA string, compute how many times each nucleotide occurs in the string.", "source": "The Calculating DNA Nucleotides_problem at Rosalind", "source_url": "https://rosalind.info/problems/dna/" } ================================================ FILE: exercises/practice/nucleotide-count/.meta/src/reference/kotlin/Dna.kt ================================================ class Dna(strand: String) { init { require(strand.matches(Regex("^[$nucleotides]*$"))) { "DNA sequence contains invalid nucleotides sequence." } } companion object Dna { const val nucleotides = "ATCG" val emptyNucleotideCounts = nucleotides.map { it to 0 }.toMap() } val nucleotideCounts: Map by lazy { emptyNucleotideCounts + strand.groupBy { it }.mapValues { it.value.size } } } ================================================ FILE: exercises/practice/nucleotide-count/.meta/tests.toml ================================================ [canonical-tests] # empty strand "3e5c30a8-87e2-4845-a815-a49671ade970" = true # can count one nucleotide in single-character input "a0ea42a6-06d9-4ac6-828c-7ccaccf98fec" = true # strand with repeated nucleotide "eca0d565-ed8c-43e7-9033-6cefbf5115b5" = true # strand with multiple nucleotides "40a45eac-c83f-4740-901a-20b22d15a39f" = true # strand with invalid nucleotides "b4c47851-ee9e-4b0a-be70-a86e343bd851" = true ================================================ FILE: exercises/practice/nucleotide-count/.meta/version ================================================ 1.3.0 ================================================ FILE: exercises/practice/nucleotide-count/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/nucleotide-count/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/nucleotide-count/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/nucleotide-count/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/nucleotide-count/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/nucleotide-count/src/main/kotlin/Dna.kt ================================================ class Dna { // TODO: Implement proper constructor val nucleotideCounts: Map get() { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/nucleotide-count/src/test/kotlin/DnaTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class DnaTest { @Test fun emptyDnaStringHasNoNucleotides() { val dna = Dna("") val expected = mapOf('A' to 0, 'C' to 0, 'G' to 0, 'T' to 0) assertEquals(expected, dna.nucleotideCounts) } @Ignore @Test fun canCountOneNucleotideInSingleCharacterInput() { val dna = Dna("G") val expected = mapOf('A' to 0, 'C' to 0, 'G' to 1, 'T' to 0) assertEquals(expected, dna.nucleotideCounts) } @Ignore @Test fun canCountRepeatedNucleotide() { val dna = Dna("GGGGGGG") val expected = mapOf('A' to 0, 'C' to 0, 'G' to 7, 'T' to 0) assertEquals(expected, dna.nucleotideCounts) } @Ignore @Test fun canCountMultipleNucleotides() { val dna = Dna("AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC") val expected = mapOf('A' to 20, 'C' to 12, 'G' to 17, 'T' to 21) assertEquals(expected, dna.nucleotideCounts) } @Ignore @Test(expected = IllegalArgumentException::class) fun validatesNucleotides() { Dna("AGXXACT") } } ================================================ FILE: exercises/practice/pangram/.docs/instructions.md ================================================ # Instructions Your task is to figure out if a sentence is a pangram. A pangram is a sentence using every letter of the alphabet at least once. It is case insensitive, so it doesn't matter if a letter is lower-case (e.g. `k`) or upper-case (e.g. `K`). For this exercise, a sentence is a pangram if it contains each of the 26 letters in the English alphabet. ================================================ FILE: exercises/practice/pangram/.docs/introduction.md ================================================ # Introduction You work for a company that sells fonts through their website. They'd like to show a different sentence each time someone views a font on their website. To give a comprehensive sense of the font, the random sentences should use **all** the letters in the English alphabet. They're running a competition to get suggestions for sentences that they can use. You're in charge of checking the submissions to see if they are valid. ~~~~exercism/note Pangram comes from Greek, παν γράμμα, pan gramma, which means "every letter". The best known English pangram is: > The quick brown fox jumps over the lazy dog. ~~~~ ================================================ FILE: exercises/practice/pangram/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "enixander", "eparovyshnaya", "jtigger", "lihofm", "markhobson", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Pangram.kt" ], "test": [ "src/test/kotlin/PangramTest.kt" ], "example": [ ".meta/src/reference/kotlin/Pangram.kt" ] }, "blurb": "Determine if a sentence is a pangram.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Pangram" } ================================================ FILE: exercises/practice/pangram/.meta/src/reference/kotlin/Pangram.kt ================================================ object Pangram { const val alphaLength = 26 fun isPangram(input: String) = input.lowercase().replace(Regex("[^a-z]"), "").toSet().size == alphaLength } ================================================ FILE: exercises/practice/pangram/.meta/tests.toml ================================================ [canonical-tests] # empty sentence "64f61791-508e-4f5c-83ab-05de042b0149" = true # perfect lower case "74858f80-4a4d-478b-8a5e-c6477e4e4e84" = true # only lower case "61288860-35ca-4abe-ba08-f5df76ecbdcd" = true # missing the letter 'x' "6564267d-8ac5-4d29-baf2-e7d2e304a743" = true # missing the letter 'h' "c79af1be-d715-4cdb-a5f2-b2fa3e7e0de0" = true # with underscores "d835ec38-bc8f-48e4-9e36-eb232427b1df" = true # with numbers "8cc1e080-a178-4494-b4b3-06982c9be2a8" = true # missing letters replaced by numbers "bed96b1c-ff95-45b8-9731-fdbdcb6ede9a" = true # mixed case and punctuation "938bd5d8-ade5-40e2-a2d9-55a338a01030" = true # case insensitive "2577bf54-83c8-402d-a64b-a2c0f7bb213a" = true ================================================ FILE: exercises/practice/pangram/.meta/version ================================================ 2.0.0 ================================================ FILE: exercises/practice/pangram/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/pangram/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/pangram/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/pangram/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/pangram/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/pangram/src/main/kotlin/Pangram.kt ================================================ object Pangram { fun isPangram(input: String): Boolean { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/pangram/src/test/kotlin/PangramTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertFalse import kotlin.test.assertTrue class PangramTest { @Test fun emptySentence() { assertFalse(Pangram.isPangram("")) } @Ignore @Test fun perfectLowerCase() { assertTrue(Pangram.isPangram("abcdefghijklmnopqrstuvwxyz")) } @Ignore @Test fun onlyLowerCase() { assertTrue(Pangram.isPangram("the quick brown fox jumps over the lazy dog")) } @Ignore @Test fun missingTheLetterX() { assertFalse(Pangram.isPangram("a quick movement of the enemy will jeopardize five gunboats")) } @Ignore @Test fun missingTheLetterH() { assertFalse(Pangram.isPangram("five boxing wizards jump quickly at it")) } @Ignore @Test fun withUnderscores() { assertTrue(Pangram.isPangram("the_quick_brown_fox_jumps_over_the_lazy_dog")) } @Ignore @Test fun withNumbers() { assertTrue(Pangram.isPangram("the 1 quick brown fox jumps over the 2 lazy dogs")) } @Ignore @Test fun missingLettersReplacedByNumbers() { assertFalse(Pangram.isPangram("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog")) } @Ignore @Test fun mixedCaseAndPunctuation() { assertTrue(Pangram.isPangram("\"Five quacking Zephyrs jolt my wax bed.\"")) } @Ignore @Test fun caseInsensitive() { assertFalse(Pangram.isPangram("the quick brown fox jumps over with lazy FX")) } } ================================================ FILE: exercises/practice/pascals-triangle/.docs/instructions.md ================================================ # Instructions Your task is to output the first N rows of Pascal's triangle. [Pascal's triangle][wikipedia] is a triangular array of positive integers. In Pascal's triangle, the number of values in a row is equal to its row number (which starts at one). Therefore, the first row has one value, the second row has two values, and so on. The first (topmost) row has a single value: `1`. Subsequent rows' values are computed by adding the numbers directly to the right and left of the current position in the previous row. If the previous row does _not_ have a value to the left or right of the current position (which only happens for the leftmost and rightmost positions), treat that position's value as zero (effectively "ignoring" it in the summation). ## Example Let's look at the first 5 rows of Pascal's Triangle: ```text 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 ``` The topmost row has one value, which is `1`. The leftmost and rightmost values have only one preceding position to consider, which is the position to its right respectively to its left. With the topmost value being `1`, it follows from this that all the leftmost and rightmost values are also `1`. The other values all have two positions to consider. For example, the fifth row's (`1 4 6 4 1`) middle value is `6`, as the values to its left and right in the preceding row are `3` and `3`: [wikipedia]: https://en.wikipedia.org/wiki/Pascal%27s_triangle ================================================ FILE: exercises/practice/pascals-triangle/.docs/introduction.md ================================================ # Introduction With the weather being great, you're not looking forward to spending an hour in a classroom. Annoyed, you enter the class room, where you notice a strangely satisfying triangle shape on the blackboard. Whilst waiting for your math teacher to arrive, you can't help but notice some patterns in the triangle: the outer values are all ones, each subsequent row has one more value than its previous row and the triangle is symmetrical. Weird! Not long after you sit down, your teacher enters the room and explains that this triangle is the famous [Pascal's triangle][wikipedia]. Over the next hour, your teacher reveals some amazing things hidden in this triangle: - It can be used to compute how many ways you can pick K elements from N values. - It contains the Fibonacci sequence. - If you color odd and even numbers differently, you get a beautiful pattern called the [Sierpiński triangle][wikipedia-sierpinski-triangle]. The teacher implores you and your classmates to look up other uses, and assures you that there are lots more! At that moment, the school bell rings. You realize that for the past hour, you were completely absorbed in learning about Pascal's triangle. You quickly grab your laptop from your bag and go outside, ready to enjoy both the sunshine _and_ the wonders of Pascal's triangle. [wikipedia]: https://en.wikipedia.org/wiki/Pascal%27s_triangle [wikipedia-sierpinski-triangle]: https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle ================================================ FILE: exercises/practice/pascals-triangle/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/PascalsTriangle.kt" ], "test": [ "src/test/kotlin/PascalsTriangleTest.kt" ], "example": [ ".meta/src/reference/kotlin/PascalsTriangle.kt" ] }, "blurb": "Compute Pascal's triangle up to a given number of rows.", "source": "Pascal's Triangle at Wolfram Math World", "source_url": "https://www.wolframalpha.com/input/?i=Pascal%27s+triangle" } ================================================ FILE: exercises/practice/pascals-triangle/.meta/src/reference/kotlin/PascalsTriangle.kt ================================================ object PascalsTriangle { fun computeTriangle(rows: Int): List> { require(rows >= 0) { "Rows can't be negative!" } if (rows == 0) return emptyList() return (1..rows).map { buildTriangleRow(it) } } private fun buildTriangleRow(row: Int): List { var m = 1 return listOf(1) + (1 until row).map { col -> m = m * (row - col) / col return@map m } } } ================================================ FILE: exercises/practice/pascals-triangle/.meta/tests.toml ================================================ [canonical-tests] # zero rows "9920ce55-9629-46d5-85d6-4201f4a4234d" = true # single row "70d643ce-a46d-4e93-af58-12d88dd01f21" = true # two rows "a6e5a2a2-fc9a-4b47-9f4f-ed9ad9fbe4bd" = true # three rows "97206a99-79ba-4b04-b1c5-3c0fa1e16925" = true # four rows "565a0431-c797-417c-a2c8-2935e01ce306" = true # five rows "06f9ea50-9f51-4eb2-b9a9-c00975686c27" = true # six rows "c3912965-ddb4-46a9-848e-3363e6b00b13" = true # ten rows "6cb26c66-7b57-4161-962c-81ec8c99f16b" = true ================================================ FILE: exercises/practice/pascals-triangle/.meta/version ================================================ 1.5.0 ================================================ FILE: exercises/practice/pascals-triangle/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/pascals-triangle/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/pascals-triangle/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/pascals-triangle/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/pascals-triangle/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/pascals-triangle/src/main/kotlin/PascalsTriangle.kt ================================================ object PascalsTriangle { fun computeTriangle(rows: Int): List> { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/pascals-triangle/src/test/kotlin/PascalsTriangleTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class PascalsTriangleTest { @Test fun `zero rows`() = assertTriangleEquals( 0, emptyList()) @Ignore @Test fun `single row`() = assertTriangleEquals( 1, listOf( listOf(1))) @Ignore @Test fun `two rows`() = assertTriangleEquals( 2, listOf( listOf(1), listOf(1, 1))) @Ignore @Test fun `tree rows`() = assertTriangleEquals( 3, listOf( listOf(1), listOf(1, 1), listOf(1, 2, 1))) @Ignore @Test fun `four rows`() = assertTriangleEquals( 4, listOf( listOf(1), listOf(1, 1), listOf(1, 2, 1), listOf(1, 3, 3, 1))) @Ignore @Test fun `five rows`() = assertTriangleEquals( 5, listOf( listOf(1), listOf(1, 1), listOf(1, 2, 1), listOf(1, 3, 3, 1), listOf(1, 4, 6, 4, 1))) @Ignore @Test fun `six rows`() = assertTriangleEquals( 6, listOf( listOf(1), listOf(1, 1), listOf(1, 2, 1), listOf(1, 3, 3, 1), listOf(1, 4, 6, 4, 1), listOf(1, 5, 10, 10, 5, 1))) @Ignore @Test fun `ten rows`() = assertTriangleEquals( 10, listOf( listOf(1), listOf(1, 1), listOf(1, 2, 1), listOf(1, 3, 3, 1), listOf(1, 4, 6, 4, 1), listOf(1, 5, 10, 10, 5, 1), listOf(1, 6, 15, 20, 15, 6, 1), listOf(1, 7, 21, 35, 35, 21, 7, 1), listOf(1, 8, 28, 56, 70, 56, 28, 8, 1), listOf(1, 9, 36, 84, 126, 126, 84, 36, 9, 1))) } private fun assertTriangleEquals(rows: Int, triangles: List>) = assertEquals(triangles, PascalsTriangle.computeTriangle(rows)) ================================================ FILE: exercises/practice/perfect-numbers/.docs/instructions.md ================================================ # Instructions Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers. The Greek mathematician [Nicomachus][nicomachus] devised a classification scheme for positive integers, identifying each as belonging uniquely to the categories of [perfect](#perfect), [abundant](#abundant), or [deficient](#deficient) based on their [aliquot sum][aliquot-sum]. The _aliquot sum_ is defined as the sum of the factors of a number not including the number itself. For example, the aliquot sum of `15` is `1 + 3 + 5 = 9`. ## Perfect A number is perfect when it equals its aliquot sum. For example: - `6` is a perfect number because `1 + 2 + 3 = 6` - `28` is a perfect number because `1 + 2 + 4 + 7 + 14 = 28` ## Abundant A number is abundant when it is less than its aliquot sum. For example: - `12` is an abundant number because `1 + 2 + 3 + 4 + 6 = 16` - `24` is an abundant number because `1 + 2 + 3 + 4 + 6 + 8 + 12 = 36` ## Deficient A number is deficient when it is greater than its aliquot sum. For example: - `8` is a deficient number because `1 + 2 + 4 = 7` - Prime numbers are deficient ## Task Implement a way to determine whether a given number is [perfect](#perfect). Depending on your language track, you may also need to implement a way to determine whether a given number is [abundant](#abundant) or [deficient](#deficient). [nicomachus]: https://en.wikipedia.org/wiki/Nicomachus [aliquot-sum]: https://en.wikipedia.org/wiki/Aliquot_sum ================================================ FILE: exercises/practice/perfect-numbers/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/NaturalNumber.kt" ], "test": [ "src/test/kotlin/NaturalNumberTest.kt" ], "example": [ ".meta/src/reference/kotlin/NaturalNumber.kt" ] }, "blurb": "Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers.", "source": "Taken from Chapter 2 of Functional Thinking by Neal Ford.", "source_url": "https://www.oreilly.com/library/view/functional-thinking/9781449365509/" } ================================================ FILE: exercises/practice/perfect-numbers/.meta/src/reference/kotlin/NaturalNumber.kt ================================================ enum class Classification { DEFICIENT, PERFECT, ABUNDANT } fun classify(naturalNumber: Int): Classification { require(naturalNumber > 0) { "$naturalNumber is not a natural number" } val aliquotSum = naturalNumber.aliquotSum() return when { aliquotSum == naturalNumber -> Classification.PERFECT aliquotSum > naturalNumber -> Classification.ABUNDANT else -> Classification.DEFICIENT } } fun Int.aliquotSum(): Int = (1 until this).filter { this % it == 0 }.sum() ================================================ FILE: exercises/practice/perfect-numbers/.meta/tests.toml ================================================ [canonical-tests] # Smallest perfect number is classified correctly "163e8e86-7bfd-4ee2-bd68-d083dc3381a3" = true # Medium perfect number is classified correctly "169a7854-0431-4ae0-9815-c3b6d967436d" = true # Large perfect number is classified correctly "ee3627c4-7b36-4245-ba7c-8727d585f402" = true # Smallest abundant number is classified correctly "80ef7cf8-9ea8-49b9-8b2d-d9cb3db3ed7e" = true # Medium abundant number is classified correctly "3e300e0d-1a12-4f11-8c48-d1027165ab60" = true # Large abundant number is classified correctly "ec7792e6-8786-449c-b005-ce6dd89a772b" = true # Smallest prime deficient number is classified correctly "e610fdc7-2b6e-43c3-a51c-b70fb37413ba" = true # Smallest non-prime deficient number is classified correctly "0beb7f66-753a-443f-8075-ad7fbd9018f3" = true # Medium deficient number is classified correctly "1c802e45-b4c6-4962-93d7-1cad245821ef" = true # Large deficient number is classified correctly "47dd569f-9e5a-4a11-9a47-a4e91c8c28aa" = true # Edge case (no factors other than itself) is classified correctly "a696dec8-6147-4d68-afad-d38de5476a56" = true # Zero is rejected (not a natural number) "72445cee-660c-4d75-8506-6c40089dc302" = true # Negative integer is rejected (not a natural number) "2d72ce2c-6802-49ac-8ece-c790ba3dae13" = true ================================================ FILE: exercises/practice/perfect-numbers/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/perfect-numbers/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/perfect-numbers/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/perfect-numbers/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/perfect-numbers/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/perfect-numbers/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/perfect-numbers/src/main/kotlin/NaturalNumber.kt ================================================ enum class Classification { DEFICIENT, PERFECT, ABUNDANT } fun classify(naturalNumber: Int): Classification { return Classification.DEFICIENT } ================================================ FILE: exercises/practice/perfect-numbers/src/test/kotlin/NaturalNumberTest.kt ================================================ import org.junit.Ignore import org.junit.Test import org.junit.Assert.assertEquals class NaturalNumberTest { @Test fun smallPerfectNumberIsClassifiedCorrectly() { assertEquals(Classification.PERFECT, classify(6)) } @Ignore @Test fun mediumPerfectNumberIsClassifiedCorrectly() { assertEquals(Classification.PERFECT, classify(28)) } @Ignore @Test fun largePerfectNumberIsClassifiedCorrectly() { assertEquals(Classification.PERFECT, classify(33550336)) } @Ignore @Test fun smallAbundantNumberIsClassifiedCorrectly() { assertEquals(Classification.ABUNDANT, classify(12)) } @Ignore @Test fun mediumAbundantNumberIsClassifiedCorrectly() { assertEquals(Classification.ABUNDANT, classify(30)) } @Ignore @Test fun largeAbundantNumberIsClassifiedCorrectly() { assertEquals(Classification.ABUNDANT, classify(33550335)) } @Ignore @Test fun smallestPrimeDeficientNumberIsClassifiedCorrectly() { assertEquals(Classification.DEFICIENT, classify(2)) } @Ignore @Test fun smallestNonPrimeDeficientNumberIsClassifiedCorrectly() { assertEquals(Classification.DEFICIENT, classify(4)) } @Ignore @Test fun mediumNumberIsClassifiedCorrectly() { assertEquals(Classification.DEFICIENT, classify(32)) } @Ignore @Test fun largeDeficientNumberIsClassifiedCorrectly() { assertEquals(Classification.DEFICIENT, classify(33550337)) } @Ignore @Test fun edgeCaseWithNoFactorsOtherThanItselfIsClassifiedCorrectly() { assertEquals(Classification.DEFICIENT, classify(1)) } @Ignore @Test(expected = RuntimeException::class) fun zeroIsNotANaturalNumber() { classify(0) } @Ignore @Test(expected = RuntimeException::class) fun negativeNumberIsNotANaturalNumber() { classify(-1) } } ================================================ FILE: exercises/practice/phone-number/.docs/instructions.md ================================================ # Instructions Clean up user-entered phone numbers so that they can be sent SMS messages. The **North American Numbering Plan (NANP)** is a telephone numbering system used by many countries in North America like the United States, Canada or Bermuda. All NANP-countries share the same international country code: `1`. NANP numbers are ten-digit numbers consisting of a three-digit Numbering Plan Area code, commonly known as _area code_, followed by a seven-digit local number. The first three digits of the local number represent the _exchange code_, followed by the unique four-digit number which is the _subscriber number_. The format is usually represented as ```text NXX NXX-XXXX ``` where `N` is any digit from 2 through 9 and `X` is any digit from 0 through 9. Sometimes they also have the country code (represented as `1` or `+1`) prefixed. Your task is to clean up differently formatted telephone numbers by removing punctuation and the country code if present. For example, the inputs - `+1 (613)-995-0253` - `613-995-0253` - `1 613 995 0253` - `613.995.0253` should all produce the output `6139950253` **Note:** As this exercise only deals with telephone numbers used in NANP-countries, only 1 is considered a valid country code. ================================================ FILE: exercises/practice/phone-number/.docs/introduction.md ================================================ # Introduction You've joined LinkLine, a leading communications company working to ensure reliable connections for everyone. The team faces a big challenge: users submit phone numbers in all sorts of formats — dashes, spaces, dots, parentheses, and even prefixes. Some numbers are valid, while others are impossible to use. Your mission is to turn this chaos into order. You'll clean up valid numbers, formatting them appropriately for use in the system. At the same time, you'll identify and filter out any invalid entries. The success of LinkLine's operations depends on your ability to separate the useful from the unusable. Are you ready to take on the challenge and keep the connections running smoothly? ================================================ FILE: exercises/practice/phone-number/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "beatbrot", "carpeliam", "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/PhoneNumber.kt" ], "test": [ "src/test/kotlin/PhoneNumberTest.kt" ], "example": [ ".meta/src/reference/kotlin/PhoneNumber.kt" ] }, "blurb": "Clean up user-entered phone numbers so that they can be sent SMS messages.", "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", "source_url": "https://turing.edu" } ================================================ FILE: exercises/practice/phone-number/.meta/src/reference/kotlin/PhoneNumber.kt ================================================ data class PhoneNumber(private val rawNumber: String) { companion object { private val invalidChars = Regex("[^\\d() -.]") private val digitsValidationRegex = Regex("^1?([2-9]\\d{2}[2-9]\\d{6})$") } val number: String? init { require(!invalidChars.containsMatchIn(rawNumber)) number = pure() ?: throw IllegalArgumentException() } private fun pure(): String? { val digits = rawNumber.replace(Regex("[^\\d]"), "") return digitsValidationRegex.matchEntire(digits)?.groupValues?.last() } } ================================================ FILE: exercises/practice/phone-number/.meta/tests.toml ================================================ [canonical-tests] # cleans the number "79666dce-e0f1-46de-95a1-563802913c35" = true # cleans numbers with dots "c360451f-549f-43e4-8aba-fdf6cb0bf83f" = true # cleans numbers with multiple spaces "08f94c34-9a37-46a2-a123-2a8e9727395d" = true # invalid when 9 digits "598d8432-0659-4019-a78b-1c6a73691d21" = true # invalid when 11 digits does not start with a 1 "57061c72-07b5-431f-9766-d97da7c4399d" = true # valid when 11 digits and starting with 1 "9962cbf3-97bb-4118-ba9b-38ff49c64430" = true # valid when 11 digits and starting with 1 even with punctuation "fa724fbf-054c-4d91-95da-f65ab5b6dbca" = true # invalid when more than 11 digits "c6a5f007-895a-4fc5-90bc-a7e70f9b5cad" = true # invalid with letters "63f38f37-53f6-4a5f-bd86-e9b404f10a60" = true # invalid with punctuations "4bd97d90-52fd-45d3-b0db-06ab95b1244e" = true # invalid if area code starts with 0 "d77d07f8-873c-4b17-8978-5f66139bf7d7" = true # invalid if area code starts with 1 "c7485cfb-1e7b-4081-8e96-8cdb3b77f15e" = true # invalid if exchange code starts with 0 "4d622293-6976-413d-b8bf-dd8a94d4e2ac" = true # invalid if exchange code starts with 1 "4cef57b4-7d8e-43aa-8328-1e1b89001262" = true # invalid if area code starts with 0 on valid 11-digit number "9925b09c-1a0d-4960-a197-5d163cbe308c" = true # invalid if area code starts with 1 on valid 11-digit number "3f809d37-40f3-44b5-ad90-535838b1a816" = true # invalid if exchange code starts with 0 on valid 11-digit number "e08e5532-d621-40d4-b0cc-96c159276b65" = true # invalid if exchange code starts with 1 on valid 11-digit number "57b32f3d-696a-455c-8bf1-137b6d171cdf" = true ================================================ FILE: exercises/practice/phone-number/.meta/version ================================================ 1.7.0 ================================================ FILE: exercises/practice/phone-number/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/phone-number/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/phone-number/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/phone-number/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/phone-number/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/phone-number/src/main/kotlin/PhoneNumber.kt ================================================ class PhoneNumber { // TODO: Implement proper constructor val number: String? = TODO("Implement this getter to complete the task") } ================================================ FILE: exercises/practice/phone-number/src/test/kotlin/PhoneNumberTest.kt ================================================ import org.junit.Ignore import org.junit.Test import java.lang.IllegalArgumentException import kotlin.test.assertEquals import kotlin.test.assertNull class PhoneNumberTest { @Test fun `valid - simple number`() = assertNumberEquals("(223) 456-7890", "2234567890") @Ignore @Test fun `valid - number with dots`() = assertNumberEquals("223.456.7890", "2234567890") @Ignore @Test fun `valid - numbers with multiple spaces`() = assertNumberEquals("223 456 7890 ", "2234567890") @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - 9 digit`() { PhoneNumber("123456789") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - when 11 digits does not start with a 1`() { PhoneNumber("22234567890") } @Ignore @Test fun `valid - 11 digits and starting with 1`() = assertNumberEquals("12234567890", "2234567890") @Ignore @Test fun `valid - 11 digits starting with 1 with punctuation`() = assertNumberEquals("+1 (223) 456-7890", "2234567890") @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - more than 11 digits`() { PhoneNumber("321234567890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - letters`() { PhoneNumber("123-abc-7890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - punctuations`() { PhoneNumber("123-@:!-7890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - area code starts with 0`() { PhoneNumber("(023) 456-7890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - area code starts with 1`() { PhoneNumber("(123) 456-7890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - exchange code starts with 0`() { PhoneNumber("(223) 056-7890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - exchange code starts with 1`() { PhoneNumber("(223) 156-7890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - area code starts with 0 on valid 11-digit number`() { PhoneNumber("1 (023) 456-7890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - area code starts with 1 on valid 11-digit number`() { PhoneNumber("1 (123) 456-7890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - exchange code starts with 0 on valid 11-digit number`() { PhoneNumber("1 (223) 056-7890") } @Ignore @Test(expected = IllegalArgumentException::class) fun `invalid - exchange code starts with 1 on valid 11-digit number`() { PhoneNumber("1 (223) 156-7890") } } private fun assertNumberEquals(input: String, expectation: String) = assertEquals(expectation, PhoneNumber(input).number) ================================================ FILE: exercises/practice/pig-latin/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "8fc23555-9445-452e-9982-c09b9716b6dc", "slug": "hashset-lookup", "title": "HashSet lookup", "blurb": "Look up values in HashSets to return the answer.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/pig-latin/.approaches/hashset-lookup/content.md ================================================ # `HashSet` lookup ```kotlin object PigLatin { private val vowels = hashSetOf('a', 'e', 'i', 'o', 'u') private val specials = hashSetOf("xr", "yt") private val vowels_y = hashSetOf('a', 'e', 'i', 'o', 'u', 'y') fun translate(phrase: String): String { return phrase.split(" ").joinToString(separator = " ") { piggyfy(it) } } private fun piggyfy(word: String): String { if (vowels.contains(word[0]) || specials.contains(word.substring(0, 2))) return word + "ay" for (pos in 1..word.length) { val letter = word[pos] if (vowels_y.contains(letter)) { val posCalc = if (letter == 'u' && word[pos - 1] == 'q') pos + 1 else pos return word.substring(posCalc) + word.substring(0, posCalc) + "ay" } } return word } } ``` An [object declaration][object] is used to define `PigLatin` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `translate` method. Three [`private`][visibility] [`val`][variables]s are defined for the [`HashSet`][hashset]s, using the [`hashSetOf`][hashsetof] method. The `translate` function is implemented by splitting the input `String` by a space, and then using the [`joinToString`][jointostring] method with a space as the separator. The [lambda][lambda] of `joinToString` uses the [`it`][it] keyword to refer to the single `String` parameter for the lambda, and passes that to the `piggyfy` function. The `translate` function returns the rejoined input `String` as transformed by each word being processed by the `piggyfy` function. The `piggyfy` function takes the input `String` and checks to see if its first character is in the `HashSet` of vowels (not including `y`) or if the first two characters are in the `HashSet` of "specials" (e.g. `"xr"` or `"yt"`). If the word starts with a vowel or a special two-letter combination, then the function returns the word concatenated with `ay` at the end. Otherwise, a [range][range] is used to iterate an index for the characters of the word in a [`for`][for-loop] loop, starting with the second character and up to but not including the length of the word. A variable is set from the character in the word at the current index of the range. If the character is in the `HashSet` of vowels (including `y`), then the index is adjusted if the current character is a `u` and the previous character is a `q`. A [`substring`][substring] is then taken from the character at the index until the end of the word. Concatenated to the end of that is a `substring` from the beginning of the word up to but not including the index. Finally, concatenated to the end of that is `ay`. The concatenated `String` is returned from the function. In the event that the word has no vowels and the `for` loop finishes without returning, the function returns the word as is. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [visibility]: https://kotlinlang.org/docs/visibility-modifiers.html [variables]: https://kotlinlang.org/docs/basic-syntax.html#variables [hashset]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-hash-set/ [hashsetof]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/hash-set-of.html [jointostring]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/join-to-string.html [lambda]: https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions [it]: https://kotlinlang.org/docs/lambdas.html#it-implicit-name-of-a-single-parameter [range]: https://kotlinlang.org/docs/ranges.html [for-loop]: https://kotlinlang.org/docs/control-flow.html#for-loops [substring]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/substring.html ================================================ FILE: exercises/practice/pig-latin/.approaches/hashset-lookup/snippet.txt ================================================ if (vowels.contains(word[0]) || specials.contains(word.substring(0, 2))) return word + "ay" for (pos in 1..word.length) { val letter = word[pos] if (vowels_y.contains(letter)) { val posCalc = if (letter == 'u' && word[pos - 1] == 'q') pos + 1 else pos return word.substring(posCalc) + word.substring(0, posCalc) + "ay" } } ================================================ FILE: exercises/practice/pig-latin/.approaches/introduction.md ================================================ # Introduction There are many ways to solve Pig Latin. One approach is to look up values from [HashSet][hashset]s. ## General guidance At the time of writing only four rules need to be handled, but if they have similar output, they don't need to be handled completely separately. ## Approach: `HashSet` lookup ```kotlin object PigLatin { private val vowels = hashSetOf('a', 'e', 'i', 'o', 'u') private val specials = hashSetOf("xr", "yt") private val vowels_y = hashSetOf('a', 'e', 'i', 'o', 'u', 'y') fun translate(phrase: String): String { return phrase.split(" ").joinToString(separator = " ") { piggyfy(it) } } private fun piggyfy(word: String): String { if (vowels.contains(word[0]) || specials.contains(word.substring(0, 2))) return word + "ay" for (pos in 1..word.length) { val letter = word[pos] if (vowels_y.contains(letter)) { val posCalc = if (letter == 'u' && word[pos - 1] == 'q') pos + 1 else pos return word.substring(posCalc) + word.substring(0, posCalc) + "ay" } } return word } } ``` For more information, check the [`HashSet` lookup approach][approach-hashset-lookup]. [approach-hashset-lookup]: https://exercism.org/tracks/kotlin/exercises/pig-latin/approaches/hashset-lookup [hashset]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-hash-set/ ================================================ FILE: exercises/practice/pig-latin/.docs/instructions.md ================================================ # Instructions Your task is to translate text from English to Pig Latin. The translation is defined using four rules, which look at the pattern of vowels and consonants at the beginning of a word. These rules look at each word's use of vowels and consonants: - vowels: the letters `a`, `e`, `i`, `o`, and `u` - consonants: the other 21 letters of the English alphabet ## Rule 1 If a word begins with a vowel, or starts with `"xr"` or `"yt"`, add an `"ay"` sound to the end of the word. For example: - `"apple"` -> `"appleay"` (starts with vowel) - `"xray"` -> `"xrayay"` (starts with `"xr"`) - `"yttria"` -> `"yttriaay"` (starts with `"yt"`) ## Rule 2 If a word begins with one or more consonants, first move those consonants to the end of the word and then add an `"ay"` sound to the end of the word. For example: - `"pig"` -> `"igp"` -> `"igpay"` (starts with single consonant) - `"chair"` -> `"airch"` -> `"airchay"` (starts with multiple consonants) - `"thrush"` -> `"ushthr"` -> `"ushthray"` (starts with multiple consonants) ## Rule 3 If a word starts with zero or more consonants followed by `"qu"`, first move those consonants (if any) and the `"qu"` part to the end of the word, and then add an `"ay"` sound to the end of the word. For example: - `"quick"` -> `"ickqu"` -> `"ickquay"` (starts with `"qu"`, no preceding consonants) - `"square"` -> `"aresqu"` -> `"aresquay"` (starts with one consonant followed by `"qu`") ## Rule 4 If a word starts with one or more consonants followed by `"y"`, first move the consonants preceding the `"y"`to the end of the word, and then add an `"ay"` sound to the end of the word. Some examples: - `"my"` -> `"ym"` -> `"ymay"` (starts with single consonant followed by `"y"`) - `"rhythm"` -> `"ythmrh"` -> `"ythmrhay"` (starts with multiple consonants followed by `"y"`) ================================================ FILE: exercises/practice/pig-latin/.docs/introduction.md ================================================ # Introduction Your parents have challenged you and your sibling to a game of two-on-two basketball. Confident they'll win, they let you score the first couple of points, but then start taking over the game. Needing a little boost, you start speaking in [Pig Latin][pig-latin], which is a made-up children's language that's difficult for non-children to understand. This will give you the edge to prevail over your parents! [pig-latin]: https://en.wikipedia.org/wiki/Pig_latin ================================================ FILE: exercises/practice/pig-latin/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/PigLatin.kt" ], "test": [ "src/test/kotlin/PigLatinTest.kt" ], "example": [ ".meta/src/reference/kotlin/PigLatin.kt" ] }, "blurb": "Implement a program that translates from English to Pig Latin.", "source": "The Pig Latin exercise at Test First Teaching by Ultrasaurus", "source_url": "https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/" } ================================================ FILE: exercises/practice/pig-latin/.meta/src/reference/kotlin/PigLatin.kt ================================================ object PigLatin { fun translate(phrase: String) = phrase.split(Regex("\\s+")).joinToString(" ") { translateWord(it) } private fun translateWord(word: String): String { if (startsWithVowelSound(word)) { return word + "ay" } val groups = splitInitialConsonantSound(word) if(groups != null) { return groups[1] + groups[0] + "ay" } return word } private val consonant = Regex("^([^aeiou]?qu|[^aeiouy]+|[^aeiou]+)([a-z]*)", RegexOption.IGNORE_CASE) private fun splitInitialConsonantSound(word: String) = consonant.matchEntire(word)?.groupValues?.drop(1) private val vowels = Regex("^([aeiou]|y[^aeiou]|xr)[a-z]*", RegexOption.IGNORE_CASE) private fun startsWithVowelSound(word: String) = vowels.matches(word) } ================================================ FILE: exercises/practice/pig-latin/.meta/tests.toml ================================================ [canonical-tests] # word beginning with a "11567f84-e8c6-4918-aedb-435f0b73db57" = true # word beginning with e "f623f581-bc59-4f45-9032-90c3ca9d2d90" = true # word beginning with i "7dcb08b3-23a6-4e8a-b9aa-d4e859450d58" = true # word beginning with o "0e5c3bff-266d-41c8-909f-364e4d16e09c" = true # word beginning with u "614ba363-ca3c-4e96-ab09-c7320799723c" = true # word beginning with a vowel and followed by a qu "bf2538c6-69eb-4fa7-a494-5a3fec911326" = true # word beginning with p "e5be8a01-2d8a-45eb-abb4-3fcc9582a303" = true # word beginning with k "d36d1e13-a7ed-464d-a282-8820cb2261ce" = true # word beginning with x "d838b56f-0a89-4c90-b326-f16ff4e1dddc" = true # word beginning with q without a following u "bce94a7a-a94e-4e2b-80f4-b2bb02e40f71" = true # word beginning with ch "c01e049a-e3e2-451c-bf8e-e2abb7e438b8" = true # word beginning with qu "9ba1669e-c43f-4b93-837a-cfc731fd1425" = true # word beginning with qu and a preceding consonant "92e82277-d5e4-43d7-8dd3-3a3b316c41f7" = true # word beginning with th "79ae4248-3499-4d5b-af46-5cb05fa073ac" = true # word beginning with thr "e0b3ae65-f508-4de3-8999-19c2f8e243e1" = true # word beginning with sch "20bc19f9-5a35-4341-9d69-1627d6ee6b43" = true # word beginning with yt "54b796cb-613d-4509-8c82-8fbf8fc0af9e" = true # word beginning with xr "8c37c5e1-872e-4630-ba6e-d20a959b67f6" = true # y is treated like a consonant at the beginning of a word "a4a36d33-96f3-422c-a233-d4021460ff00" = true # y is treated like a vowel at the end of a consonant cluster "adc90017-1a12-4100-b595-e346105042c7" = true # y as second letter in two letter word "29b4ca3d-efe5-4a95-9a54-8467f2e5e59a" = true # a whole phrase "44616581-5ce3-4a81-82d0-40c7ab13d2cf" = true ================================================ FILE: exercises/practice/pig-latin/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/pig-latin/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/pig-latin/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/pig-latin/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/pig-latin/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/pig-latin/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/pig-latin/src/main/kotlin/PigLatin.kt ================================================ object PigLatin { fun translate(phrase: String): String { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/pig-latin/src/test/kotlin/PigLatinTest.kt ================================================ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals @RunWith(Parameterized::class) class PigLatinTest(val input: String, val expectedOutput: String) { companion object { @JvmStatic @Parameterized.Parameters(name = "{index}: translate({0})={1}") fun data() = arrayOf( // Ay is added to words that start with vowels arrayOf("apple", "appleay"), arrayOf("ear", "earay"), arrayOf("igloo", "iglooay"), arrayOf("object", "objectay"), arrayOf("under", "underay"), // Ay is added to words that start with vowels followed by qu arrayOf("equal", "equalay"), // First letter and ay are moved to the end of words that start with consonants arrayOf("pig", "igpay"), arrayOf("koala", "oalakay"), arrayOf("xenon", "enonxay"), arrayOf("qat", "atqay"), // Ch is treated like a single consonant arrayOf("chair", "airchay"), // Qu is treated like a single consonant arrayOf("queen", "eenquay"), // Qu and a single preceding consonant are treated like a single consonant arrayOf("square", "aresquay"), // Th is treated like a single consonant arrayOf("therapy", "erapythay"), // Thr is treated like a single consonant arrayOf("thrush", "ushthray"), // Sch is treated like a single consonant arrayOf("school", "oolschay"), // Yt is treated like a single vowel arrayOf("yttria", "yttriaay"), // Xr is treated like a single vowel arrayOf("xray", "xrayay"), // Y is treated like a consonant at the beginning of a word arrayOf("yellow", "ellowyay"), // Y is treated like a vowel at the end of a consonant cluster arrayOf("rhythm", "ythmrhay"), // Y as second letter in two letter word arrayOf("my", "ymay"), // Phrases are translated arrayOf("quick fast run", "ickquay astfay unray") ) } @Test fun test() { assertEquals(expectedOutput, PigLatin.translate(input)) } } ================================================ FILE: exercises/practice/prime-factors/.docs/instructions.md ================================================ # Instructions Compute the prime factors of a given natural number. A prime number is only evenly divisible by itself and 1. Note that 1 is not a prime number. ## Example What are the prime factors of 60? - Our first divisor is 2. 2 goes into 60, leaving 30. - 2 goes into 30, leaving 15. - 2 doesn't go cleanly into 15. So let's move on to our next divisor, 3. - 3 goes cleanly into 15, leaving 5. - 3 does not go cleanly into 5. The next possible factor is 4. - 4 does not go cleanly into 5. The next possible factor is 5. - 5 does go cleanly into 5. - We're left only with 1, so now, we're done. Our successful divisors in that computation represent the list of prime factors of 60: 2, 2, 3, and 5. You can check this yourself: ```text 2 * 2 * 3 * 5 = 4 * 15 = 60 ``` Success! ================================================ FILE: exercises/practice/prime-factors/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/PrimeFactors.kt" ], "test": [ "src/test/kotlin/PrimeFactorCalculatorTest.kt" ], "example": [ ".meta/src/reference/kotlin/PrimeFactors.kt" ] }, "blurb": "Compute the prime factors of a given natural number.", "source": "The Prime Factors Kata by Uncle Bob", "source_url": "https://web.archive.org/web/20221026171801/http://butunclebob.com/ArticleS.UncleBob.ThePrimeFactorsKata" } ================================================ FILE: exercises/practice/prime-factors/.meta/src/reference/kotlin/PrimeFactors.kt ================================================ object PrimeFactorCalculator { fun primeFactors(int: Int): List { return primeFactors(int.toLong()).map(Long::toInt) } fun primeFactors(long: Long): List { val result = mutableListOf() var remainder = long var divisor: Long = 2 while (remainder > 1) { while (remainder.rem(divisor) == 0L) { result.add(divisor) remainder /= divisor } divisor++ } return result } } ================================================ FILE: exercises/practice/prime-factors/.meta/tests.toml ================================================ [canonical-tests] # no factors "924fc966-a8f5-4288-82f2-6b9224819ccd" = true # prime number "17e30670-b105-4305-af53-ddde182cb6ad" = true # square of a prime "f59b8350-a180-495a-8fb1-1712fbee1158" = true # cube of a prime "bc8c113f-9580-4516-8669-c5fc29512ceb" = true # product of primes and non-primes "00485cd3-a3fe-4fbe-a64a-a4308fc1f870" = true # product of primes "02251d54-3ca1-4a9b-85e1-b38f4b0ccb91" = true # factors include a large prime "070cf8dc-e202-4285-aa37-8d775c9cd473" = true ================================================ FILE: exercises/practice/prime-factors/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/prime-factors/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/prime-factors/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/prime-factors/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/prime-factors/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/prime-factors/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/prime-factors/src/main/kotlin/PrimeFactors.kt ================================================ object PrimeFactorCalculator { fun primeFactors(int: Int): List { TODO("Implement this function to complete the task") } fun primeFactors(long: Long): List { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/prime-factors/src/test/kotlin/PrimeFactorCalculatorTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class PrimeFactorCalculatorTest { @Test fun testThat1HasNoPrimeFactors() { assertEquals(emptyList(), PrimeFactorCalculator.primeFactors(1)) } @Ignore @Test fun testThatAPrimeNumberHasExactlyOnePrimeFactor() { assertEquals(listOf(2), PrimeFactorCalculator.primeFactors(2)) } @Ignore @Test fun testThatASquareOfAPrimeHasExactlyOnePrimeFactorRepeatedTwice() { assertEquals(listOf(3, 3), PrimeFactorCalculator.primeFactors(9)) } @Ignore @Test fun testThatACubeOfAPrimeHasExactlyOnePrimeFactorRepeatedThreeTimes() { assertEquals(listOf(2, 2, 2), PrimeFactorCalculator.primeFactors(8)) } @Ignore @Test fun testThatAProductOfPrimesAndNonPrimesIsFactoredProperly() { assertEquals(listOf(2, 2, 3), PrimeFactorCalculator.primeFactors(12)) } @Ignore @Test fun testThatAProductOfSmallPrimesIsFactoredProperly() { assertEquals(listOf(5, 17, 23, 461), PrimeFactorCalculator.primeFactors(901255)) } @Ignore @Test fun testThatAProductOfSmallAndLargePrimesIsFactoredProperly() { assertEquals(listOf(11, 9539, 894119), PrimeFactorCalculator.primeFactors(93819012551L)) } } ================================================ FILE: exercises/practice/protein-translation/.docs/instructions.md ================================================ # Instructions Translate RNA sequences into proteins. RNA can be broken into three-nucleotide sequences called codons, and then translated to a protein like so: RNA: `"AUGUUUUCU"` => translates to Codons: `"AUG", "UUU", "UCU"` => which become a protein with the following sequence => Protein: `"Methionine", "Phenylalanine", "Serine"` There are 64 codons which in turn correspond to 20 amino acids; however, all of the codon sequences and resulting amino acids are not important in this exercise. If it works for one codon, the program should work for all of them. However, feel free to expand the list in the test suite to include them all. There are also three terminating codons (also known as 'STOP' codons); if any of these codons are encountered (by the ribosome), all translation ends and the protein is terminated. All subsequent codons after are ignored, like this: RNA: `"AUGUUUUCUUAAAUG"` => Codons: `"AUG", "UUU", "UCU", "UAA", "AUG"` => Protein: `"Methionine", "Phenylalanine", "Serine"` Note the stop codon `"UAA"` terminates the translation and the final methionine is not translated into the protein sequence. Below are the codons and resulting amino acids needed for the exercise. | Codon | Amino Acid | | :----------------- | :------------ | | AUG | Methionine | | UUU, UUC | Phenylalanine | | UUA, UUG | Leucine | | UCU, UCC, UCA, UCG | Serine | | UAU, UAC | Tyrosine | | UGU, UGC | Cysteine | | UGG | Tryptophan | | UAA, UAG, UGA | STOP | Learn more about [protein translation on Wikipedia][protein-translation]. [protein-translation]: https://en.wikipedia.org/wiki/Translation_(biology) ================================================ FILE: exercises/practice/protein-translation/.meta/config.json ================================================ { "authors": [ "AnneKlapwijk" ], "files": { "solution": [ "src/main/kotlin/ProteinTranslation.kt" ], "test": [ "src/test/kotlin/ProteinTranslationTest.kt" ], "example": [ ".meta/src/reference/kotlin/ProteinTranslation.kt" ] }, "blurb": "Translate RNA sequences into proteins.", "source": "Tyler Long" } ================================================ FILE: exercises/practice/protein-translation/.meta/src/reference/kotlin/ProteinTranslation.kt ================================================ fun translate(rna: String?): List { if (rna.isNullOrBlank()) return emptyList() val codons = rna.chunked(3) val stopIndex = codons.indexOfFirst { listOf("UAA", "UAG", "UGA").contains(it) } return codons.subList(0, if (stopIndex > -1) stopIndex else codons.size).map { codon -> when (codon) { "AUG" -> "Methionine" "UUU", "UUC" -> "Phenylalanine" "UUA", "UUG" -> "Leucine" "UCU", "UCC", "UCA", "UCG" -> "Serine" "UAU", "UAC" -> "Tyrosine" "UGU", "UGC" -> "Cysteine" "UGG" -> "Tryptophan" else -> throw IllegalArgumentException("Invalid codon") } } } ================================================ FILE: exercises/practice/protein-translation/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [2c44f7bf-ba20-43f7-a3bf-f2219c0c3f98] description = "Empty RNA sequence results in no proteins" [96d3d44f-34a2-4db4-84cd-fff523e069be] description = "Methionine RNA sequence" [1b4c56d8-d69f-44eb-be0e-7b17546143d9] description = "Phenylalanine RNA sequence 1" [81b53646-bd57-4732-b2cb-6b1880e36d11] description = "Phenylalanine RNA sequence 2" [42f69d4f-19d2-4d2c-a8b0-f0ae9ee1b6b4] description = "Leucine RNA sequence 1" [ac5edadd-08ed-40a3-b2b9-d82bb50424c4] description = "Leucine RNA sequence 2" [8bc36e22-f984-44c3-9f6b-ee5d4e73f120] description = "Serine RNA sequence 1" [5c3fa5da-4268-44e5-9f4b-f016ccf90131] description = "Serine RNA sequence 2" [00579891-b594-42b4-96dc-7ff8bf519606] description = "Serine RNA sequence 3" [08c61c3b-fa34-4950-8c4a-133945570ef6] description = "Serine RNA sequence 4" [54e1e7d8-63c0-456d-91d2-062c72f8eef5] description = "Tyrosine RNA sequence 1" [47bcfba2-9d72-46ad-bbce-22f7666b7eb1] description = "Tyrosine RNA sequence 2" [3a691829-fe72-43a7-8c8e-1bd083163f72] description = "Cysteine RNA sequence 1" [1b6f8a26-ca2f-43b8-8262-3ee446021767] description = "Cysteine RNA sequence 2" [1e91c1eb-02c0-48a0-9e35-168ad0cb5f39] description = "Tryptophan RNA sequence" [e547af0b-aeab-49c7-9f13-801773a73557] description = "STOP codon RNA sequence 1" [67640947-ff02-4f23-a2ef-816f8a2ba72e] description = "STOP codon RNA sequence 2" [9c2ad527-ebc9-4ace-808b-2b6447cb54cb] description = "STOP codon RNA sequence 3" [f4d9d8ee-00a8-47bf-a1e3-1641d4428e54] description = "Sequence of two protein codons translates into proteins" [dd22eef3-b4f1-4ad6-bb0b-27093c090a9d] description = "Sequence of two different protein codons translates into proteins" [d0f295df-fb70-425c-946c-ec2ec185388e] description = "Translate RNA strand into correct protein list" [e30e8505-97ec-4e5f-a73e-5726a1faa1f4] description = "Translation stops if STOP codon at beginning of sequence" [5358a20b-6f4c-4893-bce4-f929001710f3] description = "Translation stops if STOP codon at end of two-codon sequence" [ba16703a-1a55-482f-bb07-b21eef5093a3] description = "Translation stops if STOP codon at end of three-codon sequence" [4089bb5a-d5b4-4e71-b79e-b8d1f14a2911] description = "Translation stops if STOP codon in middle of three-codon sequence" [2c2a2a60-401f-4a80-b977-e0715b23b93d] description = "Translation stops if STOP codon in middle of six-codon sequence" [1e75ea2a-f907-4994-ae5c-118632a1cb0f] description = "Non-existing codon can't translate" [9eac93f3-627a-4c90-8653-6d0a0595bc6f] description = "Unknown amino acids, not part of a codon, can't translate" [9d73899f-e68e-4291-b1e2-7bf87c00f024] description = "Incomplete RNA sequence can't translate" [43945cf7-9968-402d-ab9f-b8a28750b050] description = "Incomplete RNA sequence can translate if valid until a STOP codon" ================================================ FILE: exercises/practice/protein-translation/.meta/version ================================================ 1.0.0 ================================================ FILE: exercises/practice/protein-translation/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/protein-translation/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/protein-translation/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/protein-translation/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/protein-translation/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/protein-translation/src/main/kotlin/ProteinTranslation.kt ================================================ fun translate(rna: String?): List { TODO("Implement this function to complete the task") } ================================================ FILE: exercises/practice/protein-translation/src/test/kotlin/ProteinTranslationTest.kt ================================================ import org.junit.Test import org.junit.Ignore import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals import kotlin.test.assertFailsWith class ProteinTranslationTest { @Test fun emptyRNAHasNoProteins() { assertEquals(emptyList(), translate(null)) } @Ignore @Test fun `Sequence of two protein codons translates into proteins`() { assertEquals(listOf("Phenylalanine", "Phenylalanine"), translate("UUUUUU")) } @Ignore @Test fun `Sequence of two different protein codons translates into proteins`() { assertEquals(listOf("Leucine", "Leucine"), translate("UUAUUG")) } @Ignore @Test fun `Translate RNA strand into correct protein list`() { assertEquals(listOf("Methionine", "Phenylalanine", "Tryptophan"), translate("AUGUUUUGG")) } @Ignore @Test fun `Translation stops if STOP codon at beginning of sequence`() { assertEquals(emptyList(), translate("UAGUGG")) } @Ignore @Test fun `Translation stops if STOP codon at end of three-codon sequence`() { assertEquals(listOf("Methionine", "Phenylalanine"), translate("AUGUUUUAA")) } @Ignore @Test fun `Translation stops if STOP codon in middle of three-codon sequence`() { assertEquals(listOf("Tryptophan"), translate("UGGUAGUGG")) } @Ignore @Test fun `Translation stops if STOP codon in middle of six-codon sequence`() { assertEquals(listOf("Tryptophan", "Cysteine", "Tyrosine"), translate("UGGUGUUAUUAAUGGUUU")) } @Ignore @Test fun `Non-existing codon can't translate`() { assertFailsWith("Invalid codon") { translate("AAA") } } @Ignore @Test fun `Unknown amino acids, not part of a codon, can't translate`() { assertFailsWith("Invalid codon") { translate("XYZ") } } @Ignore @Test fun `Incomplete RNA sequence can't translate`() { assertFailsWith("Invalid codon") { translate("AUGU") } } @Ignore @Test fun `Incomplete RNA sequence can translate if valid until a STOP codon`() { assertEquals(listOf("Phenylalanine", "Phenylalanine"), translate("UUCUUCUAAUGGU")) } } @RunWith(Parameterized::class) class ParameterizedProteinTranslationTest(private val protein: String, private val codons: List) { companion object { @JvmStatic @Parameterized.Parameters fun data(): Collection> { return listOf( arrayOf("Methionine", listOf("AUG")), arrayOf("Phenylalanine", listOf("UUU", "UUC")), arrayOf("Leucine", listOf("UUA", "UUG")), arrayOf("Serine", listOf("UCU", "UCC", "UCA", "UCG")), arrayOf("Tyrosine", listOf("UAU", "UAC")), arrayOf("Cysteine", listOf("UGU", "UGC")), arrayOf("Tryptophan", listOf("UGG")) ) } } @Ignore @Test fun `Protein codon translates into protein`() { codons.forEachIndexed { index, codon -> val seq = index + 1 assertEquals(listOf(protein), translate(codon), "${protein} RNA sequence ${seq} translates into ${protein}") } } } ================================================ FILE: exercises/practice/rail-fence-cipher/.docs/instructions.md ================================================ # Instructions Implement encoding and decoding for the rail fence cipher. The Rail Fence cipher is a form of transposition cipher that gets its name from the way in which it's encoded. It was already used by the ancient Greeks. In the Rail Fence cipher, the message is written downwards on successive "rails" of an imaginary fence, then moving up when we get to the bottom (like a zig-zag). Finally the message is then read off in rows. For example, using three "rails" and the message "WE ARE DISCOVERED FLEE AT ONCE", the cipherer writes out: ```text W . . . E . . . C . . . R . . . L . . . T . . . E . E . R . D . S . O . E . E . F . E . A . O . C . . . A . . . I . . . V . . . D . . . E . . . N . . ``` Then reads off: ```text WECRLTEERDSOEEFEAOCAIVDEN ``` To decrypt a message you take the zig-zag shape and fill the ciphertext along the rows. ```text ? . . . ? . . . ? . . . ? . . . ? . . . ? . . . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . ``` The first row has seven spots that can be filled with "WECRLTE". ```text W . . . E . . . C . . . R . . . L . . . T . . . E . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . ``` Now the 2nd row takes "ERDSOEEFEAOC". ```text W . . . E . . . C . . . R . . . L . . . T . . . E . E . R . D . S . O . E . E . F . E . A . O . C . . . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . ``` Leaving "AIVDEN" for the last row. ```text W . . . E . . . C . . . R . . . L . . . T . . . E . E . R . D . S . O . E . E . F . E . A . O . C . . . A . . . I . . . V . . . D . . . E . . . N . . ``` If you now read along the zig-zag shape you can read the original message. ================================================ FILE: exercises/practice/rail-fence-cipher/.meta/config.json ================================================ { "authors": [ "vmichalak" ], "contributors": [ "araknoid", "dector", "eparovyshnaya", "lihofm", "mdowds", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/RailFenceCipher.kt" ], "test": [ "src/test/kotlin/RailFenceCipherTest.kt" ], "example": [ ".meta/src/reference/kotlin/RailFenceCipher.kt" ] }, "blurb": "Implement encoding and decoding for the rail fence cipher.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Transposition_cipher#Rail_Fence_cipher" } ================================================ FILE: exercises/practice/rail-fence-cipher/.meta/src/reference/kotlin/RailFenceCipher.kt ================================================ class RailFenceCipher(private val key: Int) { private val size: Int = key * 2 - 2 fun getEncryptedData(input: String): String = input .mapIndexed { i, c -> Pair(track(i), c) } .groupBy { it.first } .flatMap { it -> it.value.map { it.second } } .joinToString("") fun getDecryptedData(input: String): String = (0 until input.length) .groupBy { track(it) } .flatMap { it.value } .zip(input.asIterable()) .sortedBy { it.first } .map { it.second } .joinToString("") private fun track(index: Int) = when { isCorrect(index) -> 0 isCorrect(index - key + 1) -> key -1 else -> (1 until key).first { isCorrect(index - it) || isCorrect(index - size + it)} } private fun isCorrect(index: Int): Boolean = index % size == 0 } ================================================ FILE: exercises/practice/rail-fence-cipher/.meta/tests.toml ================================================ [canonical-tests] # encode with two rails "46dc5c50-5538-401d-93a5-41102680d068" = true # encode with three rails "25691697-fbd8-4278-8c38-b84068b7bc29" = true # encode with ending in the middle "384f0fea-1442-4f1a-a7c4-5cbc2044002c" = true # decode with three rails "cd525b17-ec34-45ef-8f0e-4f27c24a7127" = true # decode with five rails "dd7b4a98-1a52-4e5c-9499-cbb117833507" = true # decode with six rails "93e1ecf4-fac9-45d9-9cd2-591f47d3b8d3" = true ================================================ FILE: exercises/practice/rail-fence-cipher/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/rail-fence-cipher/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/rail-fence-cipher/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/rail-fence-cipher/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/rail-fence-cipher/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/rail-fence-cipher/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/rail-fence-cipher/src/main/kotlin/RailFenceCipher.kt ================================================ class RailFenceCipher { // TODO: Implement proper constructor fun getEncryptedData(input: String): String { TODO("Implement this function to complete the task") } fun getDecryptedData(input: String): String { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/rail-fence-cipher/src/test/kotlin/RailFenceCipherTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class RailFenceCipherTest { @Test fun encodeWithTwoRails() { val railFenceCipher = RailFenceCipher(2) assertEquals( "XXXXXXXXXOOOOOOOOO", railFenceCipher.getEncryptedData("XOXOXOXOXOXOXOXOXO") ) } @Ignore @Test fun encodeWithThreeRails() { val railFenceCipher = RailFenceCipher(3) assertEquals( "WECRLTEERDSOEEFEAOCAIVDEN", railFenceCipher.getEncryptedData("WEAREDISCOVEREDFLEEATONCE") ) } @Ignore @Test fun encodeWithEndingInTheMiddle() { val railFenceCipher = RailFenceCipher(4) assertEquals( "ESXIEECSR", railFenceCipher.getEncryptedData("EXERCISES") ) } @Ignore @Test fun decodeWithThreeRails() { val railFenceCipher = RailFenceCipher(3) assertEquals( "THEDEVILISINTHEDETAILS", railFenceCipher.getDecryptedData("TEITELHDVLSNHDTISEIIEA") ) } @Ignore @Test fun decodeWithFiveRails() { val railFenceCipher = RailFenceCipher(5) assertEquals( "EXERCISMISAWESOME", railFenceCipher.getDecryptedData("EIEXMSMESAORIWSCE") ); } @Ignore @Test fun decodeWithSixRails() { val railFenceCipher = RailFenceCipher(6) assertEquals( "112358132134558914423337761098715972584418167651094617711286", railFenceCipher.getDecryptedData("133714114238148966225439541018335470986172518171757571896261") ) } } ================================================ FILE: exercises/practice/raindrops/.approaches/buildstring/content.md ================================================ # `buildString` ```kotlin object Raindrops { fun convert(num: Int) = buildString { if (num % 3 == 0) append("Pling") if (num % 5 == 0) append("Plang") if (num % 7 == 0) append("Plong") if (isEmpty()) append(num) } } ``` An [object declaration][object] is used to define `Raindrops` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `convert` method. The `convert` function is implemented with a call to the [`buildString`][buildstring] function. Although the `convert` function has multiple lines, it consists only of the one `buildString` expression, so it is defined using [single-expression function][single-expression-function] syntax, with the curly braces omitted from the `convert` function call and the return type [inferred][type-inference]. The `builderAction` argument is a block of statements, each of which calls one or more methods on an implicit [`StringBuilder`][stringbuilder] object. The [modulus operator][modulus-operator] (`%`) is used to check if the input number is evenly divisible by `3`, `5`, or `7`. If so, then the [`append`][append] method is called on the`StringBuilder` to add the associated sound. After all of the numbers have been checked, the [`isEmpty`][isempty] method of `StringBuilder` is used to see if no sound was added. If no sound was added, then the input number number is automatically converted to a `String` when appended to the `StringBuilder`. The `convert` function returns the result of calling `buildString`, which is the result of the implicit call to the [`toString`][tostring] method of the `StringBuilder` after the block of statements in the `buildAction` argument. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [single-expression-function]: https://kotlinlang.org/docs/functions.html#single-expression-functions [type-inference]: https://kotlinlang.org/spec/type-inference.html [modulus-operator]: https://www.programiz.com/kotlin-programming/operators [buildstring]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/build-string.html#buildstring [stringbuilder]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-string-builder/ [append]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/append.html [isempty]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/is-empty.html [tostring]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-string-builder/to-string.html ================================================ FILE: exercises/practice/raindrops/.approaches/buildstring/snippet.txt ================================================ object Raindrops { fun convert(num: Int) = buildString { if (num % 3 == 0) append("Pling") if (num % 5 == 0) append("Plang") if (num % 7 == 0) append("Plong") if (isEmpty()) append(num) } } ================================================ FILE: exercises/practice/raindrops/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "d0608dd0-9320-46c2-af9e-e54b9d0fc354", "slug": "buildstring", "title": "buildString", "blurb": "Use buildString to return the result.", "authors": [ "bobahop" ] }, { "uuid": "7d435fdf-db16-4c89-b56f-fe71a68c1d1b", "slug": "fold-on-list", "title": "fold on a List", "blurb": "Iterate a List with fold to return the result.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/raindrops/.approaches/fold-on-list/content.md ================================================ # `fold` on a `List` ```kotlin object Raindrops { fun convert(n: Int) = listOf(3 to "Pling", 5 to "Plang", 7 to "Plong") .fold("") { output, pair -> output + if (n % pair.first == 0) pair.second else "" } .ifEmpty { n.toString() } } ``` An [object declaration][object] is used to define `Raindrops` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `convert` method. The `convert` function is implemented with a call to a chain of functions which returns a single value. Although the `convert` function has multiple lines, it consists only of the one expression resulting from the function chain, so it is defined using [single-expression function][single-expression-function] syntax, with the curly braces omitted from the `convert` function call and the return type [inferred][type-inference]. The first function is the [`listOf`][listof] method to create a [`List`][list] of [`Pair`][pair] values, using the [`to`][to] keyword to associate a number with its sound. The [`fold`][fold] method is called on the `List`. Its accumulating value is initialized with an empty `String`. The [lambda][lambda] of `fold` takes the accumulating `String` value as well as the `Pair` of each `List` element being iterated. If the input number is evenly divisible by the number in the current `Pair` being iterated, then the sound from the `Pair` is concatenated to the accumulating `String`, otherwise, an empty string is concatenated to it. The accumulating `String` is returned to the next iteration of `fold`. When `fold` has iterated through all of the `List` elements, the `StringBuilder` is the result. The `convert` function returns the result of calling the [`ifEmpty`][ifempty] method on the `StringBuilder`. If the `StringBuilder` content is empty, then it outputs the input number converterd to a `String`. Otherwise, it returns the content of the `StringBuilder` as a `String`. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [single-expression-function]: https://kotlinlang.org/docs/functions.html#single-expression-functions [type-inference]: https://kotlinlang.org/spec/type-inference.html [listof]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html [fold]: https://kotlinlang.org/docs/collection-aggregate.html#fold-and-reduce [list]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/ [pair]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/ [to]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html [lambda]: https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions [ifempty]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/if-empty.html ================================================ FILE: exercises/practice/raindrops/.approaches/fold-on-list/snippet.txt ================================================ object Raindrops { fun convert(n: Int) = listOf(3 to "Pling", 5 to "Plang", 7 to "Plong") .fold("") { output, pair -> output + if (n % pair.first == 0) pair.second else "" } .ifEmpty { n.toString() } } ================================================ FILE: exercises/practice/raindrops/.approaches/introduction.md ================================================ # Introduction There are several idiomatic ways to solve Raindrops. One way is to use the [`buildString`][buildstring] function. Another way is to use the [`fold`][fold] method on a [`List`][list]. ## General guidance The key to solving Raindrops is to know if the input is evenly divisible by `3`, `5` and/or `7`. For determining that, you will use the [modulus operator][modulus-operator]. ## Approach: `buildString` ```kotlin object Raindrops { fun convert(num: Int) = buildString { if (num % 3 == 0) append("Pling") if (num % 5 == 0) append("Plang") if (num % 7 == 0) append("Plong") if (isEmpty()) append(num) } } ``` For more information, check the [`buildString` approach][approach-buildstring]. ## Approach: `fold` on a `List` ```kotlin object Raindrops { fun convert(n: Int) = listOf(3 to "Pling", 5 to "Plang", 7 to "Plong") .fold("") { output, pair -> output + if (n % pair.first == 0) pair.second else "" } .ifEmpty { n.toString() } } ``` For more information, check the [`fold` on a `List` approach][approach-fold-on-list]. ## Which approach to use? Benchmarking is currently outside the scope of this document, so which to use is a matter of stylistic choice. An advantage for `List` is that, if another type of raindrop were to be added, only another entry would be added to the `List`, and no other code would need to be added. [approach-buildstring]: https://exercism.org/tracks/kotlin/exercises/raindrops/approaches/buildstring [approach-fold-on-list]: https://exercism.org/tracks/kotlin/exercises/raindrops/approaches/fold-on-list [modulus-operator]: https://www.programiz.com/kotlin-programming/operators [buildstring]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/build-string.html#buildstring [fold]: https://kotlinlang.org/docs/collection-aggregate.html#fold-and-reduce [list]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/ ================================================ FILE: exercises/practice/raindrops/.docs/instructions.md ================================================ # Instructions Your task is to convert a number into its corresponding raindrop sounds. If a given number: - is divisible by 3, add "Pling" to the result. - is divisible by 5, add "Plang" to the result. - is divisible by 7, add "Plong" to the result. - **is not** divisible by 3, 5, or 7, the result should be the number as a string. ## Examples - 28 is divisible by 7, but not 3 or 5, so the result would be `"Plong"`. - 30 is divisible by 3 and 5, but not 7, so the result would be `"PlingPlang"`. - 34 is not divisible by 3, 5, or 7, so the result would be `"34"`. ~~~~exercism/note A common way to test if one number is evenly divisible by another is to compare the [remainder][remainder] or [modulus][modulo] to zero. Most languages provide operators or functions for one (or both) of these. [remainder]: https://exercism.org/docs/programming/operators/remainder [modulo]: https://en.wikipedia.org/wiki/Modulo_operation ~~~~ ================================================ FILE: exercises/practice/raindrops/.docs/introduction.md ================================================ # Introduction Raindrops is a slightly more complex version of the FizzBuzz challenge, a classic interview question. ================================================ FILE: exercises/practice/raindrops/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Raindrops.kt" ], "test": [ "src/test/kotlin/RaindropsTest.kt" ], "example": [ ".meta/src/reference/kotlin/Raindrops.kt" ] }, "blurb": "Convert a number into its corresponding raindrop sounds - Pling, Plang and Plong.", "source": "A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division.", "source_url": "https://en.wikipedia.org/wiki/Fizz_buzz" } ================================================ FILE: exercises/practice/raindrops/.meta/src/reference/kotlin/Raindrops.kt ================================================ object Raindrops { private val sounds = listOf(Pair(3, "Pling"), Pair(5, "Plang"), Pair(7, "Plong")) fun convert(n: Int): String { val result = sounds.filter { n % it.first == 0 }.joinToString("") { it.second } return result.ifEmpty { n.toString() } } } ================================================ FILE: exercises/practice/raindrops/.meta/tests.toml ================================================ [canonical-tests] # the sound for 1 is 1 "1575d549-e502-46d4-a8e1-6b7bec6123d8" = true # the sound for 3 is Pling "1f51a9f9-4895-4539-b182-d7b0a5ab2913" = true # the sound for 5 is Plang "2d9bfae5-2b21-4bcd-9629-c8c0e388f3e0" = true # the sound for 7 is Plong "d7e60daa-32ef-4c23-b688-2abff46c4806" = true # the sound for 6 is Pling as it has a factor 3 "6bb4947b-a724-430c-923f-f0dc3d62e56a" = true # 2 to the power 3 does not make a raindrop sound as 3 is the exponent not the base "ce51e0e8-d9d4-446d-9949-96eac4458c2d" = true # the sound for 9 is Pling as it has a factor 3 "0dd66175-e3e2-47fc-8750-d01739856671" = true # the sound for 10 is Plang as it has a factor 5 "022c44d3-2182-4471-95d7-c575af225c96" = true # the sound for 14 is Plong as it has a factor of 7 "37ab74db-fed3-40ff-b7b9-04acdfea8edf" = true # the sound for 15 is PlingPlang as it has factors 3 and 5 "31f92999-6afb-40ee-9aa4-6d15e3334d0f" = true # the sound for 21 is PlingPlong as it has factors 3 and 7 "ff9bb95d-6361-4602-be2c-653fe5239b54" = true # the sound for 25 is Plang as it has a factor 5 "d2e75317-b72e-40ab-8a64-6734a21dece1" = true # the sound for 27 is Pling as it has a factor 3 "a09c4c58-c662-4e32-97fe-f1501ef7125c" = true # the sound for 35 is PlangPlong as it has factors 5 and 7 "bdf061de-8564-4899-a843-14b48b722789" = true # the sound for 49 is Plong as it has a factor 7 "c4680bee-69ba-439d-99b5-70c5fd1a7a83" = true # the sound for 52 is 52 "17f2bc9a-b65a-4d23-8ccd-266e8c271444" = true # the sound for 105 is PlingPlangPlong as it has factors 3, 5 and 7 "e46677ed-ff1a-419f-a740-5c713d2830e4" = true # the sound for 3125 is Plang as it has a factor 5 "13c6837a-0fcd-4b86-a0eb-20572f7deb0b" = true ================================================ FILE: exercises/practice/raindrops/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/raindrops/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/raindrops/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/raindrops/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/raindrops/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/raindrops/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/raindrops/src/main/kotlin/Raindrops.kt ================================================ object Raindrops { fun convert(n: Int): String { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/raindrops/src/test/kotlin/RaindropsTest.kt ================================================ import org.junit.Test import org.junit.Ignore import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals @RunWith(Parameterized::class) class RaindropsTest(val input: Int, val expectedOutput: String) { companion object { @JvmStatic @Parameterized.Parameters(name = "{index}: raindrops({0})={1}") fun data() = listOf( arrayOf( 1, "1"), arrayOf( 3, "Pling"), arrayOf( 5, "Plang"), arrayOf( 7, "Plong"), arrayOf( 6, "Pling"), arrayOf( 8, "8"), arrayOf( 9, "Pling"), arrayOf( 10, "Plang"), arrayOf( 14, "Plong"), arrayOf( 15, "PlingPlang"), arrayOf( 21, "PlingPlong"), arrayOf( 25, "Plang"), arrayOf( 27, "Pling"), arrayOf( 35, "PlangPlong"), arrayOf( 49, "Plong"), arrayOf( 52, "52"), arrayOf( 105, "PlingPlangPlong"), arrayOf(3125, "Plang") ) } @Test fun test() { assertEquals(expectedOutput, Raindrops.convert(input)) } } ================================================ FILE: exercises/practice/react/.docs/instructions.md ================================================ # Instructions Implement a basic reactive system. Reactive programming is a programming paradigm that focuses on how values are computed in terms of each other to allow a change to one value to automatically propagate to other values, like in a spreadsheet. Implement a basic reactive system with cells with settable values ("input" cells) and cells with values computed in terms of other cells ("compute" cells). Implement updates so that when an input value is changed, values propagate to reach a new stable system state. In addition, compute cells should allow for registering change notification callbacks. Call a cell’s callbacks when the cell’s value in a new stable state has changed from the previous stable state. ================================================ FILE: exercises/practice/react/.meta/config.json ================================================ { "authors": [ "petertseng" ], "contributors": [ "dector", "lihofm", "mdowds", "nithia", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/React.kt" ], "test": [ "src/test/kotlin/ReactTest.kt" ], "example": [ ".meta/src/reference/kotlin/React.kt" ] }, "blurb": "Implement a basic reactive system." } ================================================ FILE: exercises/practice/react/.meta/src/reference/kotlin/React.kt ================================================ class Reactor() { abstract inner class Cell { abstract val value: T internal val dependents = mutableListOf() } interface Subscription { fun cancel() } inner class InputCell(initialValue: T) : Cell() { override var value: T = initialValue set(newValue) { field = newValue dependents.forEach { it.propagate() } dependents.forEach { it.fireCallbacks() } } } inner class ComputeCell private constructor(val newValue: () -> T) : Cell() { override var value: T = newValue() private set private var lastCallbackValue = value private var callbacksIssued = 0 private val activeCallbacks = mutableMapOf Any>() constructor(vararg cells: Cell, f: (List) -> T) : this({ f(cells.map { it.value }) }) { for (cell in cells) { cell.dependents.add(this) } } fun addCallback(f: (T) -> Any): Subscription { val id = callbacksIssued callbacksIssued++ activeCallbacks[id] = f return object : Subscription { override fun cancel() { activeCallbacks.remove(id) } } } internal fun propagate() { val nv = newValue() if (nv == value) { return } value = nv dependents.forEach { it.propagate() } } internal fun fireCallbacks() { if (value == lastCallbackValue) { return } lastCallbackValue = value for (cb in activeCallbacks.values) { cb(value) } dependents.forEach { it.fireCallbacks() } } } } ================================================ FILE: exercises/practice/react/.meta/tests.toml ================================================ [canonical-tests] # input cells have a value "c51ee736-d001-4f30-88d1-0c8e8b43cd07" = true # an input cell's value can be set "dedf0fe0-da0c-4d5d-a582-ffaf5f4d0851" = true # compute cells calculate initial value "5854b975-f545-4f93-8968-cc324cde746e" = true # compute cells take inputs in the right order "25795a3d-b86c-4e91-abe7-1c340e71560c" = true # compute cells update value when dependencies are changed "c62689bf-7be5-41bb-b9f8-65178ef3e8ba" = true # compute cells can depend on other compute cells "5ff36b09-0a88-48d4-b7f8-69dcf3feea40" = true # compute cells fire callbacks "abe33eaf-68ad-42a5-b728-05519ca88d2d" = true # callback cells only fire on change "9e5cb3a4-78e5-4290-80f8-a78612c52db2" = true # callbacks do not report already reported values "ada17cb6-7332-448a-b934-e3d7495c13d3" = true # callbacks can fire from multiple cells "ac271900-ea5c-461c-9add-eeebcb8c03e5" = true # callbacks can be added and removed "95a82dcc-8280-4de3-a4cd-4f19a84e3d6f" = true # removing a callback multiple times doesn't interfere with other callbacks "f2a7b445-f783-4e0e-8393-469ab4915f2a" = true # callbacks should only be called once even if multiple dependencies change "daf6feca-09e0-4ce5-801d-770ddfe1c268" = true # callbacks should not be called if dependencies change but output value doesn't change "9a5b159f-b7aa-4729-807e-f1c38a46d377" = true ================================================ FILE: exercises/practice/react/.meta/version ================================================ 1.0.0 ================================================ FILE: exercises/practice/react/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/react/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/react/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/react/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/react/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/react/src/main/kotlin/React.kt ================================================ class Reactor() { // Your compute cell's addCallback method must return an object // that implements the Subscription interface. interface Subscription { fun cancel() } } ================================================ FILE: exercises/practice/react/src/test/kotlin/ReactTest.kt ================================================ import org.junit.Test import org.junit.Ignore import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals class ReactTest { @Test fun inputCellsHaveValue() { val reactor = Reactor() val input = reactor.InputCell(10) assertEquals(10, input.value) } @Ignore @Test fun inputCellsValueCanBeSet() { val reactor = Reactor() val input = reactor.InputCell(4) input.value = 20 assertEquals(20, input.value) } @Ignore @Test fun computeCellsCalculateInitialValue() { val reactor = Reactor() val input = reactor.InputCell(1) val output = reactor.ComputeCell(input) { it[0] + 1 } assertEquals(2, output.value) } @Ignore @Test fun computeCellsTakeInputsInTheRightOrder() { val reactor = Reactor() val one = reactor.InputCell(1) val two = reactor.InputCell(2) val output = reactor.ComputeCell(one, two) { (x, y) -> x + y * 10 } assertEquals(21, output.value) } @Ignore @Test fun computeCellsUpdateValueWhenDependenciesAreChanged() { val reactor = Reactor() val input = reactor.InputCell(1) val output = reactor.ComputeCell(input) { it[0] + 1 } input.value = 3 assertEquals(4, output.value) } @Ignore @Test fun computeCellsCanDependOnOtherComputeCells() { val reactor = Reactor() val input = reactor.InputCell(1) val timesTwo = reactor.ComputeCell(input) { it[0] * 2 } val timesThirty = reactor.ComputeCell(input) { it[0] * 30 } val output = reactor.ComputeCell(timesTwo, timesThirty) { (x, y) -> x + y } assertEquals(32, output.value) input.value = 3 assertEquals(96, output.value) } @Ignore @Test fun computeCellsFireCallbacks() { val reactor = Reactor() val input = reactor.InputCell(1) val output = reactor.ComputeCell(input) { it[0] + 1 } val vals = mutableListOf() output.addCallback { vals.add(it) } input.value = 3 assertEquals(listOf(4), vals) } @Ignore @Test fun callbacksOnlyFireOnChange() { val reactor = Reactor() val input = reactor.InputCell(1) val output = reactor.ComputeCell(input) { if (it[0] < 3) 111 else 222 } val vals = mutableListOf() output.addCallback { vals.add(it) } input.value = 2 assertEquals(listOf(), vals) input.value = 4 assertEquals(listOf(222), vals) } @Ignore @Test fun callbacksCanBeAddedAndRemoved() { val reactor = Reactor() val input = reactor.InputCell(11) val output = reactor.ComputeCell(input) { it[0] + 1 } val vals1 = mutableListOf() val sub1 = output.addCallback { vals1.add(it) } val vals2 = mutableListOf() output.addCallback { vals2.add(it) } input.value = 31 sub1.cancel() val vals3 = mutableListOf() output.addCallback { vals3.add(it) } input.value = 41 assertEquals(listOf(32), vals1) assertEquals(listOf(32, 42), vals2) assertEquals(listOf(42), vals3) } @Ignore @Test fun removingACallbackMultipleTimesDoesntInterfereWithOtherCallbacks() { val reactor = Reactor() val input = reactor.InputCell(1) val output = reactor.ComputeCell(input) { it[0] + 1 } val vals1 = mutableListOf() val sub1 = output.addCallback { vals1.add(it) } val vals2 = mutableListOf() output.addCallback { vals2.add(it) } for (i in 1..3) { sub1.cancel() } input.value = 2 assertEquals(listOf(), vals1) assertEquals(listOf(3), vals2) } @Ignore @Test fun callbacksShouldOnlyBeCalledOnceEvenIfMultipleDependenciesChange() { val reactor = Reactor() val input = reactor.InputCell(1) val plusOne = reactor.ComputeCell(input) { it[0] + 1 } val minusOne1 = reactor.ComputeCell(input) { it[0] - 1 } val minusOne2 = reactor.ComputeCell(minusOne1) { it[0] - 1 } val output = reactor.ComputeCell(plusOne, minusOne2) { (x, y) -> x * y } val vals = mutableListOf() output.addCallback { vals.add(it) } input.value = 4 assertEquals(listOf(10), vals) } @Ignore @Test fun callbacksShouldNotBeCalledIfDependenciesChangeButOutputValueDoesntChange() { val reactor = Reactor() val input = reactor.InputCell(1) val plusOne = reactor.ComputeCell(input) { it[0] + 1 } val minusOne = reactor.ComputeCell(input) { it[0] - 1 } val alwaysTwo = reactor.ComputeCell(plusOne, minusOne) { (x, y) -> x - y } val vals = mutableListOf() alwaysTwo.addCallback { vals.add(it) } for (i in 2..5) { input.value = i } assertEquals(listOf(), vals) } } /* * Extension * * This is a digital logic circuit called an adder: * https://en.wikipedia.org/wiki/Adder_(electronics) */ @RunWith(Parameterized::class) class ReactAdderTest(val input: Input, val expected: Expected) { companion object { data class Input(val a: Boolean, val b: Boolean, val carryIn: Boolean) data class Expected(val carryOut: Boolean, val sum: Boolean) @JvmStatic @Parameterized.Parameters(name = "{index}: {0} = {1}") fun data() = listOf( arrayOf(Input(a=false, b=false, carryIn=false), Expected(carryOut=false, sum=false)), arrayOf(Input(a=false, b=false, carryIn=true), Expected(carryOut=false, sum=true)), arrayOf(Input(a=false, b=true, carryIn=false), Expected(carryOut=false, sum=true)), arrayOf(Input(a=false, b=true, carryIn=true), Expected(carryOut=true, sum=false)), arrayOf(Input(a=true, b=false, carryIn=false), Expected(carryOut=false, sum=true)), arrayOf(Input(a=true, b=false, carryIn=true), Expected(carryOut=true, sum=false)), arrayOf(Input(a=true, b=true, carryIn=false), Expected(carryOut=true, sum=false)), arrayOf(Input(a=true, b=true, carryIn=true), Expected(carryOut=true, sum=true)) ) } @Ignore @Test fun test() { val reactor = Reactor() val a = reactor.InputCell(input.a) val b = reactor.InputCell(input.b) val carryIn = reactor.InputCell(input.carryIn) val aXorB = reactor.ComputeCell(a, b) { (x, y) -> x.xor(y) } val sum = reactor.ComputeCell(aXorB, carryIn) { (x, y) -> x.xor(y) } val aXorBAndCin = reactor.ComputeCell(aXorB, carryIn) { (x, y) -> x && y } val aAndB = reactor.ComputeCell(a, b) { (x, y) -> x && y } val carryOut = reactor.ComputeCell(aXorBAndCin, aAndB) { (x, y) -> x || y } assertEquals(expected, Expected(sum=sum.value, carryOut=carryOut.value)) } } ================================================ FILE: exercises/practice/resistor-color/.docs/instructions.md ================================================ # Instructions If you want to build something using a Raspberry Pi, you'll probably use _resistors_. For this exercise, you need to know two things about them: - Each resistor has a resistance value. - Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. Each band has a position and a numeric value. The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number. In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands. These colors are encoded as follows: - black: 0 - brown: 1 - red: 2 - orange: 3 - yellow: 4 - green: 5 - blue: 6 - violet: 7 - grey: 8 - white: 9 The goal of this exercise is to create a way: - to look up the numerical value associated with a particular color band - to list the different band colors Mnemonics map the colors to the numbers, that, when stored as an array, happen to map to their index in the array: Better Be Right Or Your Great Big Values Go Wrong. More information on the color encoding of resistors can be found in the [Electronic color code Wikipedia article][e-color-code]. [e-color-code]: https://en.wikipedia.org/wiki/Electronic_color_code ================================================ FILE: exercises/practice/resistor-color/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ResistorColor.kt" ], "test": [ "src/test/kotlin/ResistorColorTest.kt" ], "example": [ ".meta/src/reference/kotlin/ResistorColor.kt" ] }, "blurb": "Convert a resistor band's color to its numeric representation.", "source": "Maud de Vries, Erik Schierboom", "source_url": "https://github.com/exercism/problem-specifications/issues/1458" } ================================================ FILE: exercises/practice/resistor-color/.meta/src/reference/kotlin/ResistorColor.kt ================================================ object ResistorColor { private val colors = listOf("black", "brown", "red", "orange", "yellow", "green", "blue", "violet", "grey", "white") fun colorCode(input: String): Int = colors.indexOf(input) fun colors() = colors } ================================================ FILE: exercises/practice/resistor-color/.meta/tests.toml ================================================ [canonical-tests] # Black "49eb31c5-10a8-4180-9f7f-fea632ab87ef" = true # White "0a4df94b-92da-4579-a907-65040ce0b3fc" = true # Orange "5f81608d-f36f-4190-8084-f45116b6f380" = true # Colors "581d68fa-f968-4be2-9f9d-880f2fb73cf7" = true ================================================ FILE: exercises/practice/resistor-color/.meta/version ================================================ 1.0.0 ================================================ FILE: exercises/practice/resistor-color/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/resistor-color/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/resistor-color/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/resistor-color/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/resistor-color/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/resistor-color/src/main/kotlin/ResistorColor.kt ================================================ object ResistorColor { fun colorCode(input: String): Int { TODO("Implement this to complete the task") } fun colors(): List { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/resistor-color/src/test/kotlin/ResistorColorTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.assertEquals import kotlin.test.Test class ResistorColorTest { @Test fun testBlackColorCode() = assertEquals(0, ResistorColor.colorCode("black")) @Ignore @Test fun testWhiteColorCode() = assertEquals(9, ResistorColor.colorCode("white")) @Ignore @Test fun testOrangeColorCode() = assertEquals(3, ResistorColor.colorCode("orange")) @Ignore @Test fun testColors() { val expected = listOf("black", "brown", "red", "orange", "yellow", "green", "blue", "violet", "grey", "white") assertEquals(expected, ResistorColor.colors()) } } ================================================ FILE: exercises/practice/resistor-color-duo/.docs/instructions.md ================================================ # Instructions If you want to build something using a Raspberry Pi, you'll probably use _resistors_. For this exercise, you need to know two things about them: - Each resistor has a resistance value. - Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. Each band has a position and a numeric value. The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number. For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15. In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands. The program will take color names as input and output a two digit number, even if the input is more than two colors! The band colors are encoded as follows: - black: 0 - brown: 1 - red: 2 - orange: 3 - yellow: 4 - green: 5 - blue: 6 - violet: 7 - grey: 8 - white: 9 From the example above: brown-green should return 15, and brown-green-violet should return 15 too, ignoring the third color. ================================================ FILE: exercises/practice/resistor-color-duo/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ResistorColorDuo.kt" ], "test": [ "src/test/kotlin/ResistorColorDuoTest.kt" ], "example": [ ".meta/src/reference/kotlin/ResistorColorDuo.kt" ] }, "blurb": "Convert color codes, as used on resistors, to a numeric value.", "source": "Maud de Vries, Erik Schierboom", "source_url": "https://github.com/exercism/problem-specifications/issues/1464" } ================================================ FILE: exercises/practice/resistor-color-duo/.meta/src/reference/kotlin/Color.kt ================================================ enum class Color { BLACK, BROWN, RED, ORANGE, YELLOW, GREEN, BLUE, VIOLET, GREY, WHITE } ================================================ FILE: exercises/practice/resistor-color-duo/.meta/src/reference/kotlin/ResistorColorDuo.kt ================================================ object ResistorColorDuo { fun value(vararg colors: Color): Int = 10 * colors[0].ordinal + colors[1].ordinal } ================================================ FILE: exercises/practice/resistor-color-duo/.meta/tests.toml ================================================ [canonical-tests] # Brown and black "ce11995a-5b93-4950-a5e9-93423693b2fc" = true # Blue and grey "7bf82f7a-af23-48ba-a97d-38d59406a920" = true # Yellow and violet "f1886361-fdfd-4693-acf8-46726fe24e0c" = true # Orange and orange "77a8293d-2a83-4016-b1af-991acc12b9fe" = true # Ignore additional colors "0c4fb44f-db7c-4d03-afa8-054350f156a8" = true ================================================ FILE: exercises/practice/resistor-color-duo/.meta/version ================================================ 2.1.0 ================================================ FILE: exercises/practice/resistor-color-duo/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/resistor-color-duo/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/resistor-color-duo/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/resistor-color-duo/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/resistor-color-duo/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/resistor-color-duo/src/main/kotlin/Color.kt ================================================ enum class Color { BLACK, BROWN, RED, ORANGE, YELLOW, GREEN, BLUE, VIOLET, GREY, WHITE } ================================================ FILE: exercises/practice/resistor-color-duo/src/main/kotlin/ResistorColorDuo.kt ================================================ object ResistorColorDuo { fun value(vararg colors: Color): Int { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/resistor-color-duo/src/test/kotlin/ResistorColorDuoTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class ResistorColorDuoTest { @Test fun `brown and black`() = assertEquals(10, ResistorColorDuo.value(Color.BROWN, Color.BLACK)) @Ignore @Test fun `blue and grey`() = assertEquals(68, ResistorColorDuo.value(Color.BLUE, Color.GREY)) @Ignore @Test fun `yellow and violet`() = assertEquals(47, ResistorColorDuo.value(Color.YELLOW, Color.VIOLET)) @Ignore @Test fun `orange and orange`() = assertEquals(33, ResistorColorDuo.value(Color.ORANGE, Color.ORANGE)) @Ignore @Test fun `ignore additional colors`() = assertEquals(51, ResistorColorDuo.value(Color.GREEN, Color.BROWN, Color.ORANGE)) } ================================================ FILE: exercises/practice/resistor-color-trio/.docs/instructions.md ================================================ # Instructions If you want to build something using a Raspberry Pi, you'll probably use _resistors_. For this exercise, you need to know only three things about them: - Each resistor has a resistance value. - Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. - Each band acts as a digit of a number. For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15. In this exercise, you are going to create a helpful program so that you don't have to remember the values of the bands. The program will take 3 colors as input, and outputs the correct value, in ohms. The color bands are encoded as follows: - black: 0 - brown: 1 - red: 2 - orange: 3 - yellow: 4 - green: 5 - blue: 6 - violet: 7 - grey: 8 - white: 9 In Resistor Color Duo you decoded the first two colors. For instance: orange-orange got the main value `33`. The third color stands for how many zeros need to be added to the main value. The main value plus the zeros gives us a value in ohms. For the exercise it doesn't matter what ohms really are. For example: - orange-orange-black would be 33 and no zeros, which becomes 33 ohms. - orange-orange-red would be 33 and 2 zeros, which becomes 3300 ohms. - orange-orange-orange would be 33 and 3 zeros, which becomes 33000 ohms. (If Math is your thing, you may want to think of the zeros as exponents of 10. If Math is not your thing, go with the zeros. It really is the same thing, just in plain English instead of Math lingo.) This exercise is about translating the colors into a label: > "... ohms" So an input of `"orange", "orange", "black"` should return: > "33 ohms" When we get to larger resistors, a [metric prefix][metric-prefix] is used to indicate a larger magnitude of ohms, such as "kiloohms". That is similar to saying "2 kilometers" instead of "2000 meters", or "2 kilograms" for "2000 grams". For example, an input of `"orange", "orange", "orange"` should return: > "33 kiloohms" [metric-prefix]: https://en.wikipedia.org/wiki/Metric_prefix ================================================ FILE: exercises/practice/resistor-color-trio/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ResistorColorTrio.kt" ], "test": [ "src/test/kotlin/ResistorColorTrioTest.kt" ], "example": [ ".meta/src/reference/kotlin/ResistorColorTrio.kt" ] }, "blurb": "Convert color codes, as used on resistors, to a human-readable label.", "source": "Maud de Vries, Erik Schierboom", "source_url": "https://github.com/exercism/problem-specifications/issues/1549" } ================================================ FILE: exercises/practice/resistor-color-trio/.meta/src/reference/kotlin/Color.kt ================================================ enum class Color { BLACK, BROWN, RED, ORANGE, YELLOW, GREEN, BLUE, VIOLET, GREY, WHITE } ================================================ FILE: exercises/practice/resistor-color-trio/.meta/src/reference/kotlin/ResistorColorTrio.kt ================================================ import kotlin.math.log10 import kotlin.math.pow object ResistorColorTrio { fun text(vararg input: Color): String { val duoValue = 10 * input[0].ordinal + input[1].ordinal val trioValue = duoValue * 10.0.pow(input[2].ordinal) val thousandPowers = (log10(trioValue) / 3).toInt() val resultValue = (trioValue / 1000.0.pow(thousandPowers)).toInt() val resultUnit = Unit.values()[thousandPowers].name.lowercase() return "$resultValue $resultUnit" } } ================================================ FILE: exercises/practice/resistor-color-trio/.meta/src/reference/kotlin/Unit.kt ================================================ enum class Unit { OHMS, KILOOHMS, MEGAOHMS, GIGAOHMS, TERAOHMS, PETAOHMS, EXAOHMS } ================================================ FILE: exercises/practice/resistor-color-trio/.meta/tests.toml ================================================ [canonical-tests] # Orange and orange and black "d6863355-15b7-40bb-abe0-bfb1a25512ed" = true # Blue and grey and brown "1224a3a9-8c8e-4032-843a-5224e04647d6" = true # Red and black and red "b8bda7dc-6b95-4539-abb2-2ad51d66a207" = true # Green and brown and orange "5b1e74bc-d838-4eda-bbb3-eaba988e733b" = true # Yellow and violet and yellow "f5d37ef9-1919-4719-a90d-a33c5a6934c9" = true ================================================ FILE: exercises/practice/resistor-color-trio/.meta/version ================================================ 1.0.0 ================================================ FILE: exercises/practice/resistor-color-trio/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/resistor-color-trio/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/resistor-color-trio/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/resistor-color-trio/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/resistor-color-trio/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/resistor-color-trio/src/main/kotlin/Color.kt ================================================ enum class Color { BLACK, BROWN, RED, ORANGE, YELLOW, GREEN, BLUE, VIOLET, GREY, WHITE } ================================================ FILE: exercises/practice/resistor-color-trio/src/main/kotlin/ResistorColorTrio.kt ================================================ object ResistorColorTrio { fun text(vararg input: Color): String { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/resistor-color-trio/src/main/kotlin/Unit.kt ================================================ enum class Unit { OHMS, KILOOHMS, MEGAOHMS, GIGAOHMS, TERAOHMS, PETAOHMS, EXAOHMS } ================================================ FILE: exercises/practice/resistor-color-trio/src/test/kotlin/ResistorColorTrioTest.kt ================================================ import kotlin.test.Test import kotlin.test.assertEquals import Color.* import kotlin.test.Ignore class ResistorColorTrioTest { @Test fun `orange orange black`() = assertEquals("33 ohms", ResistorColorTrio.text(ORANGE, ORANGE, BLACK)) @Ignore @Test fun `blue grey brown`() = assertEquals("680 ohms", ResistorColorTrio.text(BLUE, GREY, BROWN)) @Ignore @Test fun `red black red`() = assertEquals("2 kiloohms", ResistorColorTrio.text(RED, BLACK, RED)) @Ignore @Test fun `green brown orange`() = assertEquals("51 kiloohms", ResistorColorTrio.text(GREEN, BROWN, ORANGE)) @Ignore @Test fun `yellow violet yellow`() = assertEquals("470 kiloohms", ResistorColorTrio.text(YELLOW, VIOLET, YELLOW)) @Ignore @Test fun `yellow violet violet`() = assertEquals("470 megaohms", ResistorColorTrio.text(YELLOW, VIOLET, VIOLET)) } ================================================ FILE: exercises/practice/reverse-string/.docs/instructions.md ================================================ # Instructions Your task is to reverse a given string. Some examples: - Turn `"stressed"` into `"desserts"`. - Turn `"strops"` into `"sports"`. - Turn `"racecar"` into `"racecar"`. ================================================ FILE: exercises/practice/reverse-string/.docs/introduction.md ================================================ # Introduction Reversing strings (reading them from right to left, rather than from left to right) is a surprisingly common task in programming. For example, in bioinformatics, reversing the sequence of DNA or RNA strings is often important for various analyses, such as finding complementary strands or identifying palindromic sequences that have biological significance. ================================================ FILE: exercises/practice/reverse-string/.meta/config.json ================================================ { "authors": [ "vmichalak" ], "contributors": [ "dector", "eparovyshnaya", "mikegehard", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ReverseString.kt" ], "test": [ "src/test/kotlin/ReverseStringTest.kt" ], "example": [ ".meta/src/reference/kotlin/ReverseString.kt" ] }, "blurb": "Reverse a given string.", "source": "Introductory challenge to reverse an input string", "source_url": "https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb" } ================================================ FILE: exercises/practice/reverse-string/.meta/src/reference/kotlin/ReverseString.kt ================================================ fun reverse(input: String): String { val result = StringBuilder() for(i in input.indices) { result.append(input[input.length - 1 - i]) } return result.toString() } ================================================ FILE: exercises/practice/reverse-string/.meta/tests.toml ================================================ [canonical-tests] # an empty string "c3b7d806-dced-49ee-8543-933fd1719b1c" = true # a word "01ebf55b-bebb-414e-9dec-06f7bb0bee3c" = true # a capitalized word "0f7c07e4-efd1-4aaa-a07a-90b49ce0b746" = true # a sentence with punctuation "71854b9c-f200-4469-9f5c-1e8e5eff5614" = true # a palindrome "1f8ed2f3-56f3-459b-8f3e-6d8d654a1f6c" = true # an even-sized word "b9e7dec1-c6df-40bd-9fa3-cd7ded010c4c" = true ================================================ FILE: exercises/practice/reverse-string/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/reverse-string/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/reverse-string/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/reverse-string/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/reverse-string/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/reverse-string/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/reverse-string/src/main/kotlin/ReverseString.kt ================================================ fun reverse(input: String): String { TODO("Implement this function to complete the task") } ================================================ FILE: exercises/practice/reverse-string/src/test/kotlin/ReverseStringTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class ReverseStringTest { @Test fun `empty string`() = assertEquals("", reverse("")) @Ignore @Test fun `single word`() = assertEquals("tobor", reverse("robot")) @Ignore @Test fun `capitalized word`() = assertEquals("nemaR", reverse("Ramen")) @Ignore @Test fun `sentence with punctuation`() = assertEquals("!yrgnuh m'I", reverse("I'm hungry!")) @Ignore @Test fun `palindrome word`() = assertEquals("racecar", reverse("racecar")) @Ignore @Test fun `even-sized word`() = assertEquals("reward", reverse("drawer")) @Ignore @Test fun `apply twice`() { val input = "input" assertEquals(input, reverse(reverse(input))) } } ================================================ FILE: exercises/practice/rna-transcription/.docs/instructions.md ================================================ # Instructions Your task is to determine the RNA complement of a given DNA sequence. Both DNA and RNA strands are a sequence of nucleotides. The four nucleotides found in DNA are adenine (**A**), cytosine (**C**), guanine (**G**), and thymine (**T**). The four nucleotides found in RNA are adenine (**A**), cytosine (**C**), guanine (**G**), and uracil (**U**). Given a DNA strand, its transcribed RNA strand is formed by replacing each nucleotide with its complement: - `G` -> `C` - `C` -> `G` - `T` -> `A` - `A` -> `U` ~~~~exercism/note If you want to look at how the inputs and outputs are structured, take a look at the examples in the test suite. ~~~~ ================================================ FILE: exercises/practice/rna-transcription/.docs/introduction.md ================================================ # Introduction You work for a bioengineering company that specializes in developing therapeutic solutions. Your team has just been given a new project to develop a targeted therapy for a rare type of cancer. ~~~~exercism/note It's all very complicated, but the basic idea is that sometimes people's bodies produce too much of a given protein. That can cause all sorts of havoc. But if you can create a very specific molecule (called a micro-RNA), it can prevent the protein from being produced. This technique is called [RNA Interference][rnai]. [rnai]: https://admin.acceleratingscience.com/ask-a-scientist/what-is-rnai/ ~~~~ ================================================ FILE: exercises/practice/rna-transcription/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "enixander", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "mutexkid", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/RnaTranscription.kt" ], "test": [ "src/test/kotlin/RnaTranscriptionTest.kt" ], "example": [ ".meta/src/reference/kotlin/RnaTranscription.kt" ] }, "blurb": "Given a DNA strand, return its RNA complement.", "source": "Hyperphysics", "source_url": "https://web.archive.org/web/20220408112140/http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html" } ================================================ FILE: exercises/practice/rna-transcription/.meta/src/reference/kotlin/RnaTranscription.kt ================================================ fun transcribeToRna(dna: String): String = dna.map { nucleotide -> when (nucleotide) { 'A' -> 'U' 'G' -> 'C' 'C' -> 'G' 'T' -> 'A' else -> nucleotide } }.joinToString("") ================================================ FILE: exercises/practice/rna-transcription/.meta/tests.toml ================================================ [canonical-tests] # Empty RNA sequence "b4631f82-c98c-4a2f-90b3-c5c2b6c6f661" = true # RNA complement of cytosine is guanine "a9558a3c-318c-4240-9256-5d5ed47005a6" = true # RNA complement of guanine is cytosine "6eedbb5c-12cb-4c8b-9f51-f8320b4dc2e7" = true # RNA complement of thymine is adenine "870bd3ec-8487-471d-8d9a-a25046488d3e" = true # RNA complement of adenine is uracil "aade8964-02e1-4073-872f-42d3ffd74c5f" = true # RNA complement "79ed2757-f018-4f47-a1d7-34a559392dbf" = true ================================================ FILE: exercises/practice/rna-transcription/.meta/version ================================================ 1.3.0 ================================================ FILE: exercises/practice/rna-transcription/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/rna-transcription/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/rna-transcription/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/rna-transcription/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/rna-transcription/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/rna-transcription/src/main/kotlin/RnaTranscription.kt ================================================ fun transcribeToRna(dna: String): String = "" ================================================ FILE: exercises/practice/rna-transcription/src/test/kotlin/RnaTranscriptionTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class RnaTranscriptionTest { @Test fun `empty RNA` ()= assertEquals("", transcribeToRna("")) @Test @Ignore fun `RNA complement of cytosine is guanine`() = assertEquals("G", transcribeToRna("C")) @Ignore @Test fun `RNA complement of guanine is cytosine`() = assertEquals("C", transcribeToRna("G")) @Ignore @Test fun `RNA complement of thymine is adenine`() = assertEquals("A", transcribeToRna("T")) @Ignore @Test fun `RNA complement of adenine is uracil`() = assertEquals("U", transcribeToRna("A")) @Ignore @Test fun `compound RNA`() = assertEquals("UGCACCAGAAUU", transcribeToRna("ACGTGGTCTTAA")) } ================================================ FILE: exercises/practice/robot-name/.docs/instructions.md ================================================ # Instructions Manage robot factory settings. When a robot comes off the factory floor, it has no name. The first time you turn on a robot, a random name is generated in the format of two uppercase letters followed by three digits, such as RX837 or BC811. Every once in a while we need to reset a robot to its factory settings, which means that its name gets wiped. The next time you ask, that robot will respond with a new random name. The names must be random: they should not follow a predictable sequence. Using random names means a risk of collisions. Your solution must ensure that every existing robot has a unique name. ================================================ FILE: exercises/practice/robot-name/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "mikegehard", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/RobotName.kt" ], "test": [ "src/test/kotlin/RobotTest.kt" ], "example": [ ".meta/src/reference/kotlin/RobotName.kt" ] }, "blurb": "Manage robot factory settings.", "source": "A debugging session with Paul Blackwell at gSchool." } ================================================ FILE: exercises/practice/robot-name/.meta/src/reference/kotlin/RobotName.kt ================================================ class Robot { companion object { val existingNames = mutableSetOf() } private var _name: String = generateName() val name: String get() = _name fun reset() { _name = generateName() } private tailrec fun generateName(): String { val randomLetters = ('A'..'Z').randomSample(2) val numbers = (0..9).randomSample(3) val newName = (randomLetters + numbers).joinToString("") return when { existingNames.add(newName) -> newName else -> generateName() } } private fun Iterable.randomSample(number: Int): Iterable = (0 until number).map { this.shuffled()[0] } } ================================================ FILE: exercises/practice/robot-name/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/robot-name/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/robot-name/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/robot-name/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/robot-name/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/robot-name/src/main/kotlin/RobotName.kt ================================================ class Robot { val name: String get() = TODO("Implement this getter to complete the task") fun reset() { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/robot-name/src/test/kotlin/RobotTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals import kotlin.test.assertNotEquals import kotlin.test.assertTrue class RobotTest { companion object { val EXPECTED_ROBOT_NAME_PATTERN = Regex("[A-Z]{2}\\d{3}") private fun isValidName(name: String) = EXPECTED_ROBOT_NAME_PATTERN.matches(name) } val robot = Robot() @Test fun hasName() { assertTrue(isValidName(robot.name), "Robot name ${robot.name} didn't match expected pattern.") } @Ignore @Test fun differentRobotsHaveDifferentNames() { assertNotEquals(robot.name, Robot().name) } @Ignore @Test fun robotRemembersItsName() { assertEquals(robot.name, robot.name) } @Ignore @Test fun resetName() { val name = robot.name robot.reset() val name2 = robot.name assertNotEquals(name, name2) assertTrue(isValidName(name2), "Robot name $name2 didn't match expected pattern.") } @Ignore @Test fun isRandom() { val iterations = 100000 val names = (0 until iterations).map { Robot().name } assertEquals(iterations, names.size) assertEquals(iterations, names.distinct().size) } } ================================================ FILE: exercises/practice/robot-simulator/.docs/instructions.md ================================================ # Instructions Write a robot simulator. A robot factory's test facility needs a program to verify robot movements. The robots have three possible movements: - turn right - turn left - advance Robots are placed on a hypothetical infinite grid, facing a particular direction (north, east, south, or west) at a set of {x,y} coordinates, e.g., {3,8}, with coordinates increasing to the north and east. The robot then receives a number of instructions, at which point the testing facility verifies the robot's new position, and in which direction it is pointing. - The letter-string "RAALAL" means: - Turn right - Advance twice - Turn left - Advance once - Turn left yet again - Say a robot starts at {7, 3} facing north. Then running this stream of instructions should leave it at {9, 4} facing west. ================================================ FILE: exercises/practice/robot-simulator/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sjwarner-bp", "SleeplessByte", "sup95", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Robot.kt" ], "test": [ "src/test/kotlin/RobotTest.kt" ], "example": [ ".meta/src/reference/kotlin/Robot.kt" ] }, "blurb": "Write a robot simulator.", "source": "Inspired by an interview question at a famous company." } ================================================ FILE: exercises/practice/robot-simulator/.meta/src/reference/kotlin/GridPosition.kt ================================================ data class GridPosition(val x: Int, val y: Int) ================================================ FILE: exercises/practice/robot-simulator/.meta/src/reference/kotlin/Orientation.kt ================================================ enum class Orientation { NORTH, EAST, SOUTH, WEST } ================================================ FILE: exercises/practice/robot-simulator/.meta/src/reference/kotlin/Robot.kt ================================================ fun Orientation.turnLeft() = Orientation.values()[Math.floorMod(ordinal - 1, Orientation.values().size)] fun Orientation.turnRight() = Orientation.values()[Math.floorMod(ordinal + 1, Orientation.values().size)] class Robot(var gridPosition: GridPosition = GridPosition(0, 0), var orientation: Orientation = Orientation.NORTH) { private fun advance() { gridPosition = when (orientation) { Orientation.NORTH -> gridPosition.copy(y = gridPosition.y + 1) Orientation.EAST -> gridPosition.copy(x = gridPosition.x + 1) Orientation.SOUTH -> gridPosition.copy(y = gridPosition.y - 1) Orientation.WEST -> gridPosition.copy(x = gridPosition.x - 1) } } private fun turnLeft() { orientation = orientation.turnLeft() } private fun turnRight() { orientation = orientation.turnRight() } fun simulate(instructions: String) { for (instruction in instructions) { when (instruction) { 'A' -> advance() 'R' -> turnRight() 'L' -> turnLeft() else -> throw IllegalArgumentException(String.format("Invalid instruction: '%s'", instruction)) } } } } ================================================ FILE: exercises/practice/robot-simulator/.meta/tests.toml ================================================ [canonical-tests] # at origin facing north "c557c16d-26c1-4e06-827c-f6602cd0785c" = true # at negative position facing south "bf0dffce-f11c-4cdb-8a5e-2c89d8a5a67d" = true # changes north to east "8cbd0086-6392-4680-b9b9-73cf491e67e5" = true # changes east to south "8abc87fc-eab2-4276-93b7-9c009e866ba1" = true # changes south to west "3cfe1b85-bbf2-4bae-b54d-d73e7e93617a" = true # changes west to north "5ea9fb99-3f2c-47bd-86f7-46b7d8c3c716" = true # changes north to west "fa0c40f5-6ba3-443d-a4b3-58cbd6cb8d63" = true # changes west to south "da33d734-831f-445c-9907-d66d7d2a92e2" = true # changes south to east "bd1ca4b9-4548-45f4-b32e-900fc7c19389" = true # changes east to north "2de27b67-a25c-4b59-9883-bc03b1b55bba" = true # facing north increments Y "f0dc2388-cddc-4f83-9bed-bcf46b8fc7b8" = true # facing south decrements Y "2786cf80-5bbf-44b0-9503-a89a9c5789da" = true # facing east increments X "84bf3c8c-241f-434d-883d-69817dbd6a48" = true # facing west decrements X "bb69c4a7-3bbf-4f64-b415-666fa72d7b04" = true # moving east and north from README "e34ac672-4ed4-4be3-a0b8-d9af259cbaa1" = true # moving west and north "f30e4955-4b47-4aa3-8b39-ae98cfbd515b" = true # moving west and south "3e466bf6-20ab-4d79-8b51-264165182fca" = true # moving east and north "41f0bb96-c617-4e6b-acff-a4b279d44514" = true ================================================ FILE: exercises/practice/robot-simulator/.meta/version ================================================ 3.2.0 ================================================ FILE: exercises/practice/robot-simulator/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/robot-simulator/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/robot-simulator/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/robot-simulator/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/robot-simulator/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/robot-simulator/src/main/kotlin/GridPosition.kt ================================================ data class GridPosition(val x: Int, val y: Int) ================================================ FILE: exercises/practice/robot-simulator/src/main/kotlin/Orientation.kt ================================================ enum class Orientation { NORTH, EAST, SOUTH, WEST } ================================================ FILE: exercises/practice/robot-simulator/src/main/kotlin/Robot.kt ================================================ class Robot { // TODO: implement proper constructor, provide read access to `gridPosition` and `orientation` fun simulate(instructions: String) { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/robot-simulator/src/test/kotlin/RobotTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class RobotTest { @Test fun `brand new - at origin facing north`() = Robot() .should { face(Orientation.NORTH) beAt(x = 0, y = 0) } @Ignore @Test fun `brand new - at negative position facing south`() = Robot(GridPosition(x = -1, y = -1), Orientation.SOUTH) .should { face(Orientation.SOUTH) beAt(x = -1, y = -1) } @Ignore @Test fun `rotating clockwise - changes north to east`() = Robot(GridPosition(x = 0, y = 0), Orientation.NORTH) .instructed("R") .should { face(Orientation.EAST) } @Ignore @Test fun `rotating clockwise - changes east to south`() = Robot(GridPosition(x = 0, y = 0), Orientation.EAST) .instructed("R") .should { face(Orientation.SOUTH) } @Ignore @Test fun `rotating clockwise - changes south to west`() = Robot(GridPosition(x = 0, y = 0), Orientation.SOUTH) .instructed("R") .should { face(Orientation.WEST) } @Ignore @Test fun `rotating clockwise - changes west to north`() = Robot(GridPosition(x = 0, y = 0), Orientation.WEST) .instructed("R") .should { face(Orientation.NORTH) } @Ignore @Test fun `rotating counter-clockwise - changes north to west`() = Robot(GridPosition(x = 0, y = 0), Orientation.NORTH) .instructed("L") .should { face(Orientation.WEST) } @Ignore @Test fun `rotating counter-clockwise - changes west to south`() = Robot(GridPosition(x = 0, y = 0), Orientation.WEST) .instructed("L") .should { face(Orientation.SOUTH) } @Ignore @Test fun `rotating counter-clockwise - changes south to east`() = Robot(GridPosition(x = 0, y = 0), Orientation.SOUTH) .instructed("L") .should { face(Orientation.EAST) } @Ignore @Test fun `rotating counter-clockwise - changes east to north`() = Robot(GridPosition(x = 0, y = 0), Orientation.EAST) .instructed("L") .should { face(Orientation.NORTH) } @Ignore @Test fun `moving forward - facing north increments Y`() = Robot(GridPosition(x = 0, y = 0), Orientation.NORTH) .instructed("A") .should { face(Orientation.NORTH) beAt(x = 0, y = 1) } @Ignore @Test fun `moving forward - facing south decrements Y`() = Robot(GridPosition(x = 0, y = 0), Orientation.SOUTH) .instructed("A") .should { face (Orientation.SOUTH) beAt(x = 0, y = -1) } @Ignore @Test fun `moving forward - facing east increments X`() = Robot(GridPosition(x = 0, y = 0), Orientation.EAST) .instructed("A") .should { face (Orientation.EAST) beAt(x = 1, y = 0) } @Ignore @Test fun `moving forward - facing west decrements X`() = Robot(GridPosition(x = 0, y = 0), Orientation.WEST) .instructed("A") .should { face (Orientation.WEST) beAt(x = -1, y = 0) } @Ignore @Test fun `series of instructions - moving east and north example`() = Robot(GridPosition(x = 7, y = 3), Orientation.NORTH) .instructed("RAALAL") .should { face(Orientation.WEST) beAt(x = 9, y = 4) } @Ignore @Test fun `series of instructions - moving west and north`() = Robot(GridPosition(x = 0, y = 0), Orientation.NORTH) .instructed("LAAARALA") .should { face(Orientation.WEST) beAt(x = -4, y = 1) } @Ignore @Test fun `series of instructions - moving west and south`() = Robot(GridPosition(x = 2, y = -7), Orientation.EAST) .instructed("RRAAAAALA") .should { face(Orientation.SOUTH) beAt(x = -3, y = -8) } @Ignore @Test fun `series of instructions - moving east and north`() = Robot(GridPosition(x = 8, y = 4), Orientation.SOUTH) .instructed("LAAARRRALLLL") .should { face(Orientation.NORTH) beAt(x = 11, y = 5) } } private fun Robot.instructed(moves: String): Robot { simulate(moves) return this } private fun Robot.should(what: RobotShould.() -> Unit) = what(RobotShould(this)) private class RobotShould(private val robot: Robot) { fun face(expected: Orientation) = assertEquals(expected, robot.orientation) fun beAt(x: Int, y: Int) = assertEquals(GridPosition(x = x, y = y), robot.gridPosition) } ================================================ FILE: exercises/practice/roman-numerals/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "96ce2094-949d-4576-a2d1-ab8a76081225", "slug": "fold-repeat", "title": "fold with repeat", "blurb": "Use fold with repeat to return the answer.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/roman-numerals/.approaches/fold-repeat/content.md ================================================ # `fold` with `repeat` ```kotlin object RomanNumerals { fun value(n: Int) = listOf( 1000 to "M", 900 to "CM", 500 to "D", 400 to "CD", 100 to "C", 90 to "XC", 50 to "L", 40 to "XL", 10 to "X", 9 to "IX", 5 to "V", 4 to "IV", 1 to "I" ) .fold(Pair(StringBuilder(), n)) { (output, runnyNum), (value, numeral) -> when { runnyNum >= value -> output.append(numeral.repeat(runnyNum / value)) to runnyNum % value else -> output to runnyNum } } .first .toString() } ``` An [object declaration][object] is used to define `RomanNumerals` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `value` method. The [`listOf`][listof] method is used to create a list of [`Pair`][pair]s that associate an Arabic numeral with its Roman numeral. The [`fold`][fold] method is called on the `List`. Its accumulating value is initialized with a `Pair`, with a [`StringBuilder`][stringbuilder] for the output and an `Int` to hold the value of the input number as it is calculated down. The [lambda][lambda] of `fold` takes the accumulating value `Pair` as well as the `Pair` of each `List` element being iterated. The running number is tested in a [`when`][when] expression. If it is greater than or equal to the Arabic value in the currently iterated `Pair`, then the [`repeat`][repeat] method is used to [`append`][append] the Roman numeral to the `StringBuilder` for as many times as the running number can be divided by the Arabic value with a result greater than 0. That arm of the `when` uses the [`to`][to] keyword to return the `StringBuilder` and the remainder of dividing the running number by the Arabic value. If the running number is less than the Arabic value, then the `when` expression returns the `StringBuilder` and the running number as is. When `fold` has iterated through all of the `List` elements, the first item in the accumulating value `Pair` is the `StringBuilder`. The `value` function returns the result of calling the [`toString`][tostring] method on the `StringBuilder`. Although the `value` function has multiple lines, it consists only of the one expression of chained methods, so it is defined using [single-expression function][single-expression-function] syntax, with the curly braces omitted and the return type [inferred][type-inference]. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [listof]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html [list]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/ [pair]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/ [fold]: https://kotlinlang.org/docs/collection-aggregate.html#fold-and-reduce [stringbuilder]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-string-builder/ [when]: https://kotlinlang.org/docs/control-flow.html#when-expression [lambda]: https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions [append]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-string-builder/append.html [repeat]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/repeat.html [to]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html [tostring]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-string-builder/to-string.html [single-expression-function]: https://kotlinlang.org/docs/functions.html#single-expression-functions [type-inference]: https://kotlinlang.org/spec/type-inference.html ================================================ FILE: exercises/practice/roman-numerals/.approaches/fold-repeat/snippet.txt ================================================ .fold(Pair(StringBuilder(), n)) { (output, runnyNum), (value, numeral) -> when { runnyNum >= value -> output.append(numeral.repeat(runnyNum / value)) to runnyNum % value else -> output to runnyNum } } ================================================ FILE: exercises/practice/roman-numerals/.approaches/introduction.md ================================================ # Introduction There are many ways to solve Roman Numerals. One approach can use the [`fold`][fold] method on a list of [`Pair`][pair]s that associate the Arabic numeral with the Roman numeral. ## Approach: `fold` with `repeat` ```kotlin object RomanNumerals { fun value(n: Int) = listOf( 1000 to "M", 900 to "CM", 500 to "D", 400 to "CD", 100 to "C", 90 to "XC", 50 to "L", 40 to "XL", 10 to "X", 9 to "IX", 5 to "V", 4 to "IV", 1 to "I" ) .fold(Pair(StringBuilder(), n)) { (output, runnyNum), (value, numeral) -> when { runnyNum >= value -> output.append(numeral.repeat(runnyNum / value)) to runnyNum % value else -> output to runnyNum } } .first .toString() } ``` For more information, check the [`fold` with `repeat` approach][approach-fold-repeat]. [approach-fold-repeat]: https://exercism.org/tracks/kotlin/exercises/roman-numerals/approaches/fold-repeat [fold]: https://kotlinlang.org/docs/collection-aggregate.html#fold-and-reduce [pair]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/ ================================================ FILE: exercises/practice/roman-numerals/.docs/instructions.md ================================================ # Introduction Your task is to convert a number from Arabic numerals to Roman numerals. For this exercise, we are only concerned about traditional Roman numerals, in which the largest number is MMMCMXCIX (or 3,999). ~~~~exercism/note There are lots of different ways to convert between Arabic and Roman numerals. We recommend taking a naive approach first to familiarise yourself with the concept of Roman numerals and then search for more efficient methods. Make sure to check out our Deep Dive video at the end to explore the different approaches you can take! ~~~~ ================================================ FILE: exercises/practice/roman-numerals/.docs/introduction.md ================================================ # Description Today, most people in the world use Arabic numerals (0–9). But if you travelled back two thousand years, you'd find that most Europeans were using Roman numerals instead. To write a Roman numeral we use the following Latin letters, each of which has a value: | M | D | C | L | X | V | I | | ---- | --- | --- | --- | --- | --- | --- | | 1000 | 500 | 100 | 50 | 10 | 5 | 1 | A Roman numeral is a sequence of these letters, and its value is the sum of the letters' values. For example, `XVIII` has the value 18 (`10 + 5 + 1 + 1 + 1 = 18`). There's one rule that makes things trickier though, and that's that **the same letter cannot be used more than three times in succession**. That means that we can't express numbers such as 4 with the seemingly natural `IIII`. Instead, for those numbers, we use a subtraction method between two letters. So we think of `4` not as `1 + 1 + 1 + 1` but instead as `5 - 1`. And slightly confusingly to our modern thinking, we write the smaller number first. This applies only in the following cases: 4 (`IV`), 9 (`IX`), 40 (`XL`), 90 (`XC`), 400 (`CD`) and 900 (`CM`). Order matters in Roman numerals! Letters (and the special compounds above) must be ordered by decreasing value from left to right. Here are some examples: ```text 105 => CV ---- => -- 100 => C + 5 => V ``` ```text 106 => CVI ---- => -- 100 => C + 5 => V + 1 => I ``` ```text 104 => CIV ---- => --- 100 => C + 4 => IV ``` And a final more complex example: ```text 1996 => MCMXCVI ----- => ------- 1000 => M + 900 => CM + 90 => XC + 5 => V + 1 => I ``` ================================================ FILE: exercises/practice/roman-numerals/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "sup95", "uzilan" ], "files": { "solution": [ "src/main/kotlin/RomanNumerals.kt" ], "test": [ "src/test/kotlin/RomanNumeralsTest.kt" ], "example": [ ".meta/src/reference/kotlin/RomanNumerals.kt" ] }, "blurb": "Convert modern Arabic numbers into Roman numerals.", "source": "The Roman Numeral Kata", "source_url": "https://codingdojo.org/kata/RomanNumerals/" } ================================================ FILE: exercises/practice/roman-numerals/.meta/src/reference/kotlin/RomanNumerals.kt ================================================ object RomanNumerals { private val numeralValues = listOf( Pair(1000, "M"), Pair(900, "CM"), Pair(500, "D"), Pair(400, "CD"), Pair(100, "C"), Pair(90, "XC"), Pair(50, "L"), Pair(40, "XL"), Pair(10, "X"), Pair(9, "IX"), Pair(5, "V"), Pair(4, "IV"), Pair(1, "I") ) private tailrec fun fromNumber(n: Int, numerals: String): String { val numeralPair = numeralValues.find { it.first <= n } if (numeralPair != null) { return fromNumber(n - numeralPair.first, numerals + numeralPair.second) } return numerals } fun value(n: Int) = fromNumber(n, "") } ================================================ FILE: exercises/practice/roman-numerals/.meta/tests.toml ================================================ [canonical-tests] # 1 is a single I "19828a3a-fbf7-4661-8ddd-cbaeee0e2178" = true # 2 is two I's "f088f064-2d35-4476-9a41-f576da3f7b03" = true # 3 is three I's "b374a79c-3bea-43e6-8db8-1286f79c7106" = true # 4, being 5 - 1, is IV "05a0a1d4-a140-4db1-82e8-fcc21fdb49bb" = true # 5 is a single V "57c0f9ad-5024-46ab-975d-de18c430b290" = true # 6, being 5 + 1, is VI "20a2b47f-e57f-4797-a541-0b3825d7f249" = true # 9, being 10 - 1, is IX "ff3fb08c-4917-4aab-9f4e-d663491d083d" = true # 20 is two X's "2bda64ca-7d28-4c56-b08d-16ce65716cf6" = true # 48 is not 50 - 2 but rather 40 + 8 "a1f812ef-84da-4e02-b4f0-89c907d0962c" = true # 49 is not 40 + 5 + 4 but rather 50 - 10 + 10 - 1 "607ead62-23d6-4c11-a396-ef821e2e5f75" = true # 50 is a single L "d5b283d4-455d-4e68-aacf-add6c4b51915" = true # 90, being 100 - 10, is XC "46b46e5b-24da-4180-bfe2-2ef30b39d0d0" = true # 100 is a single C "30494be1-9afb-4f84-9d71-db9df18b55e3" = true # 60, being 50 + 10, is LX "267f0207-3c55-459a-b81d-67cec7a46ed9" = true # 400, being 500 - 100, is CD "cdb06885-4485-4d71-8bfb-c9d0f496b404" = true # 500 is a single D "6b71841d-13b2-46b4-ba97-dec28133ea80" = true # 900, being 1000 - 100, is CM "432de891-7fd6-4748-a7f6-156082eeca2f" = true # 1000 is a single M "e6de6d24-f668-41c0-88d7-889c0254d173" = true # 3000 is three M's "bb550038-d4eb-4be2-a9ce-f21961ac3bc6" = true ================================================ FILE: exercises/practice/roman-numerals/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/roman-numerals/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/roman-numerals/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/roman-numerals/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/roman-numerals/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/roman-numerals/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/roman-numerals/src/main/kotlin/RomanNumerals.kt ================================================ object RomanNumerals { fun value(n: Int): String { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/roman-numerals/src/test/kotlin/RomanNumeralsTest.kt ================================================ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals @RunWith(Parameterized::class) class RomanNumeralsTest(val input: Int, val expectedOutput: String) { companion object { @JvmStatic @Parameterized.Parameters(name = "{index}: romanNumeral({0})={1}") fun data() = listOf( arrayOf(1, "I"), arrayOf(2, "II"), arrayOf(3, "III"), arrayOf(4, "IV"), arrayOf(5, "V"), arrayOf(6, "VI"), arrayOf(9, "IX"), arrayOf(27, "XXVII"), arrayOf(48, "XLVIII"), arrayOf(49, "XLIX"), arrayOf(59, "LIX"), arrayOf(93, "XCIII"), arrayOf(141, "CXLI"), arrayOf(163, "CLXIII"), arrayOf(402, "CDII"), arrayOf(575, "DLXXV"), arrayOf(911, "CMXI"), arrayOf(1024, "MXXIV"), arrayOf(3000, "MMM") ) } @Test fun test() { assertEquals(expectedOutput, RomanNumerals.value(input)) } } ================================================ FILE: exercises/practice/rotational-cipher/.docs/instructions.md ================================================ # Instructions Create an implementation of the rotational cipher, also sometimes called the Caesar cipher. The Caesar cipher is a simple shift cipher that relies on transposing all the letters in the alphabet using an integer key between `0` and `26`. Using a key of `0` or `26` will always yield the same output due to modular arithmetic. The letter is shifted for as many values as the value of the key. The general notation for rotational ciphers is `ROT + `. The most commonly used rotational cipher is `ROT13`. A `ROT13` on the Latin alphabet would be as follows: ```text Plain: abcdefghijklmnopqrstuvwxyz Cipher: nopqrstuvwxyzabcdefghijklm ``` It is stronger than the Atbash cipher because it has 27 possible keys, and 25 usable keys. Ciphertext is written out in the same formatting as the input including spaces and punctuation. ## Examples - ROT5 `omg` gives `trl` - ROT0 `c` gives `c` - ROT26 `Cool` gives `Cool` - ROT13 `The quick brown fox jumps over the lazy dog.` gives `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` - ROT13 `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` gives `The quick brown fox jumps over the lazy dog.` ================================================ FILE: exercises/practice/rotational-cipher/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/RotationalCipher.kt" ], "test": [ "src/test/kotlin/RotationalCipherTest.kt" ], "example": [ ".meta/src/reference/kotlin/RotationalCipher.kt" ] }, "blurb": "Create an implementation of the rotational cipher, also sometimes called the Caesar cipher.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Caesar_cipher" } ================================================ FILE: exercises/practice/rotational-cipher/.meta/src/reference/kotlin/RotationalCipher.kt ================================================ class RotationalCipher(val shiftKey: Int) { companion object { private val LOWERS = ('a'..'z').toList() private val UPPERS = ('A'..'Z').toList() } fun encode(text: String): String { return text.map { char -> when (char) { in LOWERS -> LOWERS[(LOWERS.indexOf(char) + shiftKey) % LOWERS.size] in UPPERS -> UPPERS[(UPPERS.indexOf(char) + shiftKey) % UPPERS.size] else -> char } }.joinToString("") } } ================================================ FILE: exercises/practice/rotational-cipher/.meta/tests.toml ================================================ [canonical-tests] # rotate a by 0, same output as input "74e58a38-e484-43f1-9466-877a7515e10f" = true # rotate a by 1 "7ee352c6-e6b0-4930-b903-d09943ecb8f5" = true # rotate a by 26, same output as input "edf0a733-4231-4594-a5ee-46a4009ad764" = true # rotate m by 13 "e3e82cb9-2a5b-403f-9931-e43213879300" = true # rotate n by 13 with wrap around alphabet "19f9eb78-e2ad-4da4-8fe3-9291d47c1709" = true # rotate capital letters "a116aef4-225b-4da9-884f-e8023ca6408a" = true # rotate spaces "71b541bb-819c-4dc6-a9c3-132ef9bb737b" = true # rotate numbers "ef32601d-e9ef-4b29-b2b5-8971392282e6" = true # rotate punctuation "32dd74f6-db2b-41a6-b02c-82eb4f93e549" = true # rotate all letters "9fb93fe6-42b0-46e6-9ec1-0bf0a062d8c9" = true ================================================ FILE: exercises/practice/rotational-cipher/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/rotational-cipher/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/rotational-cipher/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/rotational-cipher/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/rotational-cipher/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/rotational-cipher/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/rotational-cipher/src/main/kotlin/RotationalCipher.kt ================================================ class RotationalCipher { // TODO: Implement proper constructor fun encode(text: String): String { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/rotational-cipher/src/test/kotlin/RotationalCipherTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class RotationalCipherTest { @Test fun testRotateLowercaseABy0() { val cipher = RotationalCipher(0) assertEquals("a", cipher.encode("a")) } @Ignore @Test fun testRotateLowercaseABy1NoWrapAround() { val cipher = RotationalCipher(1) assertEquals("b", cipher.encode("a")) } @Ignore @Test fun testRotateLowercaseABy26SingleWrapAround() { val cipher = RotationalCipher(26) assertEquals("a", cipher.encode("a")) } @Ignore @Test fun testRotateLowercaseMBy13NoWrapAround() { val cipher = RotationalCipher(13) assertEquals("z", cipher.encode("m")) } @Ignore @Test fun testRotateLowercaseNBy1SingleWrapAround() { val cipher = RotationalCipher(13) assertEquals("a", cipher.encode("n")) } @Ignore @Test fun testRotateCapitalLettersNoWrapAround() { val cipher = RotationalCipher(5) assertEquals("TRL", cipher.encode("OMG")) } @Ignore @Test fun testSpacesAreUnalteredByRotation() { val cipher = RotationalCipher(5) assertEquals("T R L", cipher.encode("O M G")) } @Ignore @Test fun testNumbersAreUnalteredByRotation() { val cipher = RotationalCipher(4) assertEquals("Xiwxmrk 1 2 3 xiwxmrk", cipher.encode("Testing 1 2 3 testing")) } @Ignore @Test fun testPunctuationIsUnalteredByRotation() { val cipher = RotationalCipher(21) assertEquals("Gzo'n zvo, Bmviyhv!", cipher.encode("Let's eat, Grandma!")) } @Ignore @Test fun testAllLettersRotateCorrectly() { val cipher = RotationalCipher(13) assertEquals( "Gur dhvpx oebja sbk whzcf bire gur ynml qbt.", cipher.encode("The quick brown fox jumps over the lazy dog.")) } } ================================================ FILE: exercises/practice/run-length-encoding/.docs/instructions.md ================================================ # Instructions Implement run-length encoding and decoding. Run-length encoding (RLE) is a simple form of data compression, where runs (consecutive data elements) are replaced by just one data value and count. For example we can represent the original 53 characters with only 13. ```text "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB" -> "12WB12W3B24WB" ``` RLE allows the original data to be perfectly reconstructed from the compressed data, which makes it a lossless data compression. ```text "AABCCCDEEEE" -> "2AB3CD4E" -> "AABCCCDEEEE" ``` For simplicity, you can assume that the unencoded string will only contain the letters A through Z (either lower or upper case) and whitespace. This way data to be encoded will never contain any numbers and numbers inside data to be decoded always represent the count for the following character. ================================================ FILE: exercises/practice/run-length-encoding/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya" ], "files": { "solution": [ "src/main/kotlin/RunLengthEncoding.kt" ], "test": [ "src/test/kotlin/RunLengthEncodingTest.kt" ], "example": [ ".meta/src/reference/kotlin/RunLengthEncoding.kt" ] }, "blurb": "Implement run-length encoding and decoding.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Run-length_encoding" } ================================================ FILE: exercises/practice/run-length-encoding/.meta/src/reference/kotlin/RunLengthEncoding.kt ================================================ import java.util.regex.Pattern object RunLengthEncoding { private val encodePattern = Pattern.compile("""([ a-zA-Z])\1*""") private val decodePattern = Pattern.compile("""(|\d+)([ a-zA-Z])""") fun encode(input: String): String { val matcher = encodePattern.matcher(input) val matcherSeq = generateSequence { if (matcher.find()) matcher else null } return matcherSeq.joinToString("") { val characters = it.group(0) val count = if (characters.length == 1) "" else characters.length.toString() count + characters.first() } } fun decode(input: String): String { val matcher = decodePattern.matcher(input) val matcherSeq = generateSequence { if (matcher.find()) matcher else null } return matcherSeq.joinToString("") { val count = if (it.group(1) == "") 1 else it.group(1).toInt() val character = it.group(2) character.repeat(count) } } } ================================================ FILE: exercises/practice/run-length-encoding/.meta/tests.toml ================================================ [canonical-tests] # empty string "ad53b61b-6ffc-422f-81a6-61f7df92a231" = true # single characters only are encoded without count "52012823-b7e6-4277-893c-5b96d42f82de" = true # string with no single characters "b7868492-7e3a-415f-8da3-d88f51f80409" = true # single characters mixed with repeated characters "859b822b-6e9f-44d6-9c46-6091ee6ae358" = true # multiple whitespace mixed in string "1b34de62-e152-47be-bc88-469746df63b3" = true # lowercase characters "abf176e2-3fbd-40ad-bb2f-2dd6d4df721a" = true # empty string "7ec5c390-f03c-4acf-ac29-5f65861cdeb5" = true # single characters only "ad23f455-1ac2-4b0e-87d0-b85b10696098" = true # string with no single characters "21e37583-5a20-4a0e-826c-3dee2c375f54" = true # single characters with repeated characters "1389ad09-c3a8-4813-9324-99363fba429c" = true # multiple whitespace mixed in string "3f8e3c51-6aca-4670-b86c-a213bf4706b0" = true # lower case string "29f721de-9aad-435f-ba37-7662df4fb551" = true # encode followed by decode gives original string "2a762efd-8695-4e04-b0d6-9736899fbc16" = true ================================================ FILE: exercises/practice/run-length-encoding/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/run-length-encoding/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/run-length-encoding/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/run-length-encoding/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/run-length-encoding/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/run-length-encoding/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/run-length-encoding/src/main/kotlin/RunLengthEncoding.kt ================================================ object RunLengthEncoding { fun encode(input: String): String { TODO("Implement this to complete the task") } fun decode(input: String): String { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/run-length-encoding/src/test/kotlin/RunLengthEncodingTest.kt ================================================ import kotlin.test.Test import kotlin.test.assertEquals import RunLengthEncoding.encode import RunLengthEncoding.decode import kotlin.test.Ignore class RunLengthEncodingTest { @Test fun `encode_empty string`() = assertEquals("", encode("")) @Ignore @Test fun `encode_single characters only are encoded without count`() = assertEquals("XYZ", encode("XYZ")) @Ignore @Test fun `encode_string with no single characters`() = assertEquals("2A3B4C", encode("AABBBCCCC")) @Ignore @Test fun `encode_single characters mixed with repeated characters`() = assertEquals("12WB12W3B24WB", encode("WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB")) @Ignore @Test fun `encode_multiple whitespace mixed in string`() = assertEquals("2 hs2q q2w2 ", encode(" hsqq qww ")) @Ignore @Test fun `encode_lowercase characters`() = assertEquals("2a3b4c", encode("aabbbcccc")) @Ignore @Test fun `decode_empty string`() = assertEquals("", decode("")) @Ignore @Test fun `decode_single characters only`() = assertEquals("XYZ", decode("XYZ")) @Ignore @Test fun `decode_string with no single characters`() = assertEquals("AABBBCCCC", decode("2A3B4C")) @Ignore @Test fun `decode_single characters with repeated characters`() = assertEquals("WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB", decode("12WB12W3B24WB")) @Ignore @Test fun `decode_multiple whitespace mixed in string`() = assertEquals(" hsqq qww ", decode("2 hs2q q2w2 ")) @Ignore @Test fun `decode_lower case string`() = assertEquals("aabbbcccc", decode("2a3b4c")) @Ignore @Test fun `encode followed by decode gives original string`() = assertEquals("zzz ZZ zZ", decode(encode("zzz ZZ zZ"))) } ================================================ FILE: exercises/practice/saddle-points/.docs/instructions.md ================================================ # Instructions Your task is to find the potential trees where you could build your tree house. The data company provides the data as grids that show the heights of the trees. The rows of the grid represent the east-west direction, and the columns represent the north-south direction. An acceptable tree will be the largest in its row, while being the smallest in its column. A grid might not have any good trees at all. Or it might have one, or even several. Here is a grid that has exactly one candidate tree. ```text ↓ 1 2 3 4 |----------- 1 | 9 8 7 8 → 2 |[5] 3 2 4 3 | 6 6 7 1 ``` - Row 2 has values 5, 3, 2, and 4. The largest value is 5. - Column 1 has values 9, 5, and 6. The smallest value is 5. So the point at `[2, 1]` (row: 2, column: 1) is a great spot for a tree house. ================================================ FILE: exercises/practice/saddle-points/.docs/introduction.md ================================================ # Introduction You plan to build a tree house in the woods near your house so that you can watch the sun rise and set. You've obtained data from a local survey company that show the height of every tree in each rectangular section of the map. You need to analyze each grid on the map to find good trees for your tree house. A good tree is both: - taller than every tree to the east and west, so that you have the best possible view of the sunrises and sunsets. - shorter than every tree to the north and south, to minimize the amount of tree climbing. ================================================ FILE: exercises/practice/saddle-points/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Matrix.kt" ], "test": [ "src/test/kotlin/MatrixTest.kt" ], "example": [ ".meta/src/reference/kotlin/Matrix.kt" ] }, "blurb": "Detect saddle points in a matrix.", "source": "J Dalbey's Programming Practice problems", "source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html" } ================================================ FILE: exercises/practice/saddle-points/.meta/src/reference/kotlin/Matrix.kt ================================================ data class Matrix(val entries: List>) { val saddlePoints: Set by lazy { val result = mutableSetOf() if (entries.isNotEmpty()) { for (row in entries.indices) { for (col in entries[0].indices) { val coordinateValue = entries[row][col] if (coordinateValue == getRowMax(row) && coordinateValue == getColumnMin(col)) { result.add(MatrixCoordinate(row + 1, col + 1)) } } } } result } private fun getRowMax(row: Int): Int { return entries[row].maxOrNull() ?: 0 } private fun getColumnMin(col: Int): Int { return entries .map { row -> row[col] } .minOrNull() ?: 0 } } ================================================ FILE: exercises/practice/saddle-points/.meta/src/reference/kotlin/MatrixCoordinate.kt ================================================ data class MatrixCoordinate(val row: Int, val col: Int) ================================================ FILE: exercises/practice/saddle-points/.meta/tests.toml ================================================ [canonical-tests] # Can identify single saddle point "3e374e63-a2e0-4530-a39a-d53c560382bd" = true # Can identify that empty matrix has no saddle points "6b501e2b-6c1f-491f-b1bb-7f278f760534" = true # Can identify lack of saddle points when there are none "8c27cc64-e573-4fcb-a099-f0ae863fb02f" = true # Can identify multiple saddle points in a column "6d1399bd-e105-40fd-a2c9-c6609507d7a3" = true # Can identify multiple saddle points in a row "3e81dce9-53b3-44e6-bf26-e328885fd5d1" = true # Can identify saddle point in bottom right corner "88868621-b6f4-4837-bb8b-3fad8b25d46b" = true # Can identify saddle points in a non square matrix "5b9499ca-fcea-4195-830a-9c4584a0ee79" = true # Can identify that saddle points in a single column matrix are those with the minimum value "ee99ccd2-a1f1-4283-ad39-f8c70f0cf594" = true # Can identify that saddle points in a single row matrix are those with the maximum value "63abf709-a84b-407f-a1b3-456638689713" = true ================================================ FILE: exercises/practice/saddle-points/.meta/version ================================================ 1.5.0 ================================================ FILE: exercises/practice/saddle-points/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/saddle-points/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/saddle-points/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/saddle-points/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/saddle-points/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/saddle-points/src/main/kotlin/Matrix.kt ================================================ data class MatrixCoordinate(val row: Int, val col: Int) ================================================ FILE: exercises/practice/saddle-points/src/test/kotlin/MatrixTest.kt ================================================ import org.junit.Ignore import org.junit.Test import java.util.Collections.emptySet import kotlin.test.assertEquals class MatrixTest { @Test fun `single saddle point`() = assertSaddlePointsEqual( Matrix( listOf( listOf(9, 8, 7), listOf(5, 3, 2), listOf(6, 6, 7) ) ), setOf( MatrixCoordinate(2, 1) ) ) @Ignore @Test fun `no saddle points for empty matrix`() = assertSaddlePointsEqual( Matrix(listOf(emptyList())), emptySet() ) @Ignore @Test fun `no saddle points for nonempty matrix`() = assertSaddlePointsEqual( Matrix( listOf( listOf(1, 2, 3), listOf(3, 1, 2), listOf(2, 3, 1) ) ), emptySet() ) @Ignore @Test fun `multiple saddle points in a column`() = assertSaddlePointsEqual( Matrix( listOf( listOf(4, 5, 4), listOf(3, 5, 5), listOf(1, 5, 4) ) ), setOf( MatrixCoordinate(1, 2), MatrixCoordinate(2, 2), MatrixCoordinate(3, 2) ) ) @Ignore @Test fun `multiple saddle points in a row`() = assertSaddlePointsEqual( Matrix( listOf( listOf(6, 7, 8), listOf(5, 5, 5), listOf(7, 5, 6) ) ), setOf( MatrixCoordinate(2, 1), MatrixCoordinate(2, 2), MatrixCoordinate(2, 3) ) ) @Ignore @Test fun `saddle point in bottom right corner`() = assertSaddlePointsEqual( Matrix( listOf( listOf(8, 7, 9), listOf(6, 7, 6), listOf(3, 2, 5) ) ), setOf( MatrixCoordinate(3, 3) ) ) @Ignore @Test fun `saddle points in a single column matrix`() = assertSaddlePointsEqual( Matrix( listOf( listOf(2), listOf(1), listOf(4), listOf(1) ) ), setOf( MatrixCoordinate(2, 1), MatrixCoordinate(4, 1) ) ) @Ignore @Test fun `saddle points in a single row matrix`() = assertSaddlePointsEqual( Matrix( listOf( listOf(2, 5, 3, 5) ) ), setOf( MatrixCoordinate(1, 2), MatrixCoordinate(1, 4) ) ) } private fun assertSaddlePointsEqual(matrix: Matrix, coordinates: Set) = assertEquals(coordinates, matrix.saddlePoints) ================================================ FILE: exercises/practice/say/.docs/instructions.md ================================================ # Instructions Given a number from 0 to 999,999,999,999, spell out that number in English. ## Step 1 Handle the basic case of 0 through 99. If the input to the program is `22`, then the output should be `'twenty-two'`. Your program should complain loudly if given a number outside the blessed range. Some good test cases for this program are: - 0 - 14 - 50 - 98 - -1 - 100 ### Extension If you're on a Mac, shell out to Mac OS X's `say` program to talk out loud. If you're on Linux or Windows, eSpeakNG may be available with the command `espeak`. ## Step 2 Implement breaking a number up into chunks of thousands. So `1234567890` should yield a list like 1, 234, 567, and 890, while the far simpler `1000` should yield just 1 and 0. ## Step 3 Now handle inserting the appropriate scale word between those chunks. So `1234567890` should yield `'1 billion 234 million 567 thousand 890'` The program must also report any values that are out of range. It's fine to stop at "trillion". ## Step 4 Put it all together to get nothing but plain English. `12345` should give `twelve thousand three hundred forty-five`. The program must also report any values that are out of range. ================================================ FILE: exercises/practice/say/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "katrinleinweber", "lihofm", "mdowds", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Say.kt" ], "test": [ "src/test/kotlin/NumberSpellerTest.kt" ], "example": [ ".meta/src/reference/kotlin/Say.kt" ] }, "blurb": "Given a number from 0 to 999,999,999,999, spell out that number in English.", "source": "A variation on the JavaRanch CattleDrive, Assignment 4", "source_url": "https://web.archive.org/web/20240907035912/https://coderanch.com/wiki/718804" } ================================================ FILE: exercises/practice/say/.meta/src/reference/kotlin/Say.kt ================================================ class NumberSpeller { companion object { val wordMap = mapOf( Pair( 0, "zero" ), Pair( 1, "one" ), Pair( 2, "two" ), Pair( 3, "three" ), Pair( 4, "four" ), Pair( 5, "five" ), Pair( 6, "six" ), Pair( 7, "seven" ), Pair( 8, "eight" ), Pair( 9, "nine" ), Pair(10, "ten" ), Pair(11, "eleven" ), Pair(12, "twelve" ), Pair(13, "thirteen" ), Pair(14, "fourteen" ), Pair(15, "fifteen" ), Pair(16, "sixteen" ), Pair(17, "seventeen"), Pair(18, "eighteen" ), Pair(19, "nineteen" ), Pair(20, "twenty" ), Pair(30, "thirty" ), Pair(40, "forty" ), Pair(50, "fifty" ), Pair(60, "sixty" ), Pair(70, "seventy" ), Pair(80, "eighty" ), Pair(90, "ninety" ) ) const val te = 10 const val hu = 100 const val th = 1000 const val mi = 1000000 const val bi = 1000000000 const val tr = 1000000000000 } fun say(input: Long): String { require(input >= 0) { "Input must be non-negative" } require(input < tr) { "Input must be less than $tr" } if (input < 20) return wordMap[input]!! if (input < hu) { return if (input % te == 0L) { wordMap[input]!! } else { "${wordMap[input / te * te]}-${wordMap[input % te]!!}" } } if (input < th) { return if (input % hu == 0L) { "${wordMap[input / hu]!!} hundred" } else { "${wordMap[input / hu]!!} hundred ${say(input % hu)}" } } if (input < mi) { return if (input % th == 0L) { "${say(input / th)} thousand" } else { "${say(input / th)} thousand ${say(input % th)}" } } if (input < bi) { return if (input % mi == 0L) { "${say(input / mi)} million" } else { "${say(input / mi)} million ${say(input % mi)}" } } return if (input % bi == 0L) { "${say(input / bi)} billion" } else { "${say(input / bi)} billion ${say(input % bi)}" } } } ================================================ FILE: exercises/practice/say/.meta/tests.toml ================================================ [canonical-tests] # zero "5d22a120-ba0c-428c-bd25-8682235d83e8" = true # one "9b5eed77-dbf6-439d-b920-3f7eb58928f6" = true # fourteen "7c499be1-612e-4096-a5e1-43b2f719406d" = true # twenty "f541dd8e-f070-4329-92b4-b7ce2fcf06b4" = true # twenty-two "d78601eb-4a84-4bfa-bf0e-665aeb8abe94" = true # one hundred "e417d452-129e-4056-bd5b-6eb1df334dce" = true # one hundred twenty-three "d6924f30-80ba-4597-acf6-ea3f16269da8" = true # one thousand "3d83da89-a372-46d3-b10d-de0c792432b3" = true # one thousand two hundred thirty-four "865af898-1d5b-495f-8ff0-2f06d3c73709" = true # one million "b6a3f442-266e-47a3-835d-7f8a35f6cf7f" = true # one million two thousand three hundred forty-five "2cea9303-e77e-4212-b8ff-c39f1978fc70" = true # one billion "3e240eeb-f564-4b80-9421-db123f66a38f" = true # a big number "9a43fed1-c875-4710-8286-5065d73b8a9e" = true # numbers below zero are out of range "49a6a17b-084e-423e-994d-a87c0ecc05ef" = true # numbers above 999,999,999,999 are out of range "4d6492eb-5853-4d16-9d34-b0f61b261fd9" = true ================================================ FILE: exercises/practice/say/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/say/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/say/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/say/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/say/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/say/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/say/src/main/kotlin/Say.kt ================================================ class NumberSpeller { fun say(input: Long): String { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/say/src/test/kotlin/NumberSpellerTest.kt ================================================ import org.junit.Ignore import org.junit.Test import java.lang.IllegalArgumentException import kotlin.test.assertEquals class NumberSpellerTest { @Test fun `0 as zero`() = 0.shouldSoundLike("zero") @Ignore @Test fun `1 as one`() = 1.shouldSoundLike("one") @Ignore @Test fun `14 as fourteen`() = 14.shouldSoundLike("fourteen") @Ignore @Test fun `20 as twenty`() = 20.shouldSoundLike("twenty") @Ignore @Test fun `22 as twenty-two`() = 22.shouldSoundLike("twenty-two") @Ignore @Test fun `100 as one hundred`() = 100.shouldSoundLike("one hundred") @Ignore @Test fun `123 as one hundred twenty-three`() = 123.shouldSoundLike("one hundred twenty-three") @Ignore @Test fun `1000 as one thousand`() = 1000.shouldSoundLike("one thousand") @Ignore @Test fun `1234 as one thousand two hundred thirty-four`() = 1234.shouldSoundLike("one thousand two hundred thirty-four") @Ignore @Test fun `1000000 as one million`() = 1000000.shouldSoundLike("one million") @Ignore @Test fun `1002345 as one million two thousand three hundred forty-five`() = 1002345.shouldSoundLike("one million two thousand three hundred forty-five") @Ignore @Test fun `1000000000 as one billion`() = 1000000000.shouldSoundLike("one billion") @Ignore @Test fun `spell a big number`() = 987654321123 .shouldSoundLike("nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three") @Ignore @Test(expected = IllegalArgumentException::class) fun `numbers below zero are out of range`() { NumberSpeller().say(-1) } @Ignore @Test(expected = IllegalArgumentException::class) fun `numbers above 999,999,999,999 are out of range`() { NumberSpeller().say(1000000000000) } } private fun Long.shouldSoundLike(expected: String) = assertEquals(expected, NumberSpeller().say(this)) private fun Int.shouldSoundLike(expected: String) = this.toLong().shouldSoundLike(expected) ================================================ FILE: exercises/practice/scale-generator/.docs/instructions.md ================================================ # Instructions ## Chromatic Scales Scales in Western music are based on the chromatic (12-note) scale. This scale can be expressed as the following group of pitches: > A, A♯, B, C, C♯, D, D♯, E, F, F♯, G, G♯ A given sharp note (indicated by a ♯) can also be expressed as the flat of the note above it (indicated by a ♭) so the chromatic scale can also be written like this: > A, B♭, B, C, D♭, D, E♭, E, F, G♭, G, A♭ The major and minor scale and modes are subsets of this twelve-pitch collection. They have seven pitches, and are called diatonic scales. The collection of notes in these scales is written with either sharps or flats, depending on the tonic (starting note). Here is a table indicating whether the flat expression or sharp expression of the scale would be used for a given tonic: | Key Signature | Major | Minor | | ------------- | --------------------- | -------------------- | | Natural | C | a | | Sharp | G, D, A, E, B, F♯ | e, b, f♯, c♯, g♯, d♯ | | Flat | F, B♭, E♭, A♭, D♭, G♭ | d, g, c, f, b♭, e♭ | Note that by common music theory convention the natural notes "C" and "a" follow the sharps scale when ascending and the flats scale when descending. For the scope of this exercise the scale is only ascending. ### Task Given a tonic, generate the 12 note chromatic scale starting with the tonic. - Shift the base scale appropriately so that all 12 notes are returned starting with the given tonic. - For the given tonic, determine if the scale is to be returned with flats or sharps. - Return all notes in uppercase letters (except for the `b` for flats) irrespective of the casing of the given tonic. ## Diatonic Scales The diatonic scales, and all other scales that derive from the chromatic scale, are built upon intervals. An interval is the space between two pitches. The simplest interval is between two adjacent notes, and is called a "half step", or "minor second" (sometimes written as a lower-case "m"). The interval between two notes that have an interceding note is called a "whole step" or "major second" (written as an upper-case "M"). The diatonic scales are built using only these two intervals between adjacent notes. Non-diatonic scales can contain other intervals. An "augmented second" interval, written "A", has two interceding notes (e.g., from A to C or D♭ to E) or a "whole step" plus a "half step". There are also smaller and larger intervals, but they will not figure into this exercise. ### Task Given a tonic and a set of intervals, generate the musical scale starting with the tonic and following the specified interval pattern. This is similar to generating chromatic scales except that instead of returning 12 notes, you will return N+1 notes for N intervals. The first note is always the given tonic. Then, for each interval in the pattern, the next note is determined by starting from the previous note and skipping the number of notes indicated by the interval. For example, starting with G and using the seven intervals MMmMMMm, there would be the following eight notes: | Note | Reason | | ---- | ------------------------------------------------- | | G | Tonic | | A | M indicates a whole step from G, skipping G♯ | | B | M indicates a whole step from A, skipping A♯ | | C | m indicates a half step from B, skipping nothing | | D | M indicates a whole step from C, skipping C♯ | | E | M indicates a whole step from D, skipping D♯ | | F♯ | M indicates a whole step from E, skipping F | | G | m indicates a half step from F♯, skipping nothing | ================================================ FILE: exercises/practice/scale-generator/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "jmrunkle" ], "files": { "solution": [ "src/main/kotlin/Scale.kt" ], "test": [ "src/test/kotlin/ScaleTest.kt" ], "example": [ ".meta/src/reference/kotlin/Scale.kt" ] }, "blurb": "Generate musical scales, given a starting note and a set of intervals." } ================================================ FILE: exercises/practice/scale-generator/.meta/src/reference/kotlin/Scale.kt ================================================ class Scale(private val tonic: String) { companion object { private val sharps = listOf("A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#") private val flats = listOf("A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab") private val useFlats = listOf("F", "Bb", "Eb", "Ab", "Db", "Gb", "d", "g", "c", "f", "bb", "eb") private val intervalOffsets = mapOf('m' to 1, 'M' to 2, 'A' to 3) } private val orderedChromatic: List init { val notes = if (useFlats.contains(tonic)) flats else sharps val start = notes.indexOfFirst { it.lowercase() == tonic.lowercase() } orderedChromatic = notes.subList(start, notes.size) + notes.subList(0, start) } fun chromatic(): List = orderedChromatic fun interval(intervals: String): List { var idx = 0 return intervals.map { val note = orderedChromatic[idx] idx += intervalOffsets[it] ?: error("Unkown interval $it!") note } } } ================================================ FILE: exercises/practice/scale-generator/.meta/tests.toml ================================================ [canonical-tests] # Chromatic scale with sharps "10ea7b14-8a49-40be-ac55-7c62b55f9b47" = true # Chromatic scale with flats "af8381de-9a72-4efd-823a-48374dbfe76f" = true # Simple major scale "6f5b1410-1dd7-4c6c-b410-6b7e986f6f1e" = true # Major scale with sharps "13a92f89-a83e-40b5-b9d4-01136931ba02" = true # Major scale with flats "aa3320f6-a761-49a1-bcf6-978e0c81080a" = true # Minor scale with sharps "63daeb2f-c3f9-4c45-92be-5bf97f61ff94" = true # Minor scale with flats "616594d0-9c48-4301-949e-af1d4fad16fd" = true # Dorian mode "390bd12c-5ac7-4ec7-bdde-4e58d5c78b0a" = true # Mixolydian mode "846d0862-0f3e-4f3b-8a2d-9cc74f017848" = true # Lydian mode "7d49a8bb-b5f7-46ad-a207-83bd5032291a" = true # Phrygian mode "a4e4dac5-1891-4160-a19f-bb06d653d4d0" = true # Locrian mode "ef3650af-90f8-4ad9-9ef6-fdbeae07dcaa" = true # Harmonic minor "70517400-12b7-4530-b861-fa940ae69ee8" = true # Octatonic "37114c0b-c54d-45da-9f4b-3848201470b0" = true # Hexatonic "496466e7-aa45-4bbd-a64d-f41030feed9c" = true # Pentatonic "bee5d9ec-e226-47b6-b62b-847a9241f3cc" = true # Enigmatic "dbee06a6-7535-4ab7-98e8-d8a36c8402d1" = true ================================================ FILE: exercises/practice/scale-generator/.meta/version ================================================ 2.0.0 ================================================ FILE: exercises/practice/scale-generator/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/scale-generator/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/scale-generator/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/scale-generator/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/scale-generator/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/scale-generator/src/main/kotlin/Scale.kt ================================================ class Scale(private val tonic: String) { fun chromatic(): List { TODO("Implement this function to complete the task") } fun interval(intervals: String): List { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/scale-generator/src/test/kotlin/ScaleTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.asserter import kotlin.test.Test class ScaleTest { // Test chromatic scales @Test fun `chromatic scale with sharps`() { val expected = listOf("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") assertScalesEqual(expected, Scale("C").chromatic()) } @Ignore @Test fun `chromatic scale with flats`() { val expected = listOf("F", "Gb", "G", "Ab", "A", "Bb", "B", "C", "Db", "D", "Eb", "E") assertScalesEqual(expected, Scale("F").chromatic()) } // Test scales with specified intervals @Ignore @Test fun `simple major scale`() { val expected = listOf("C", "D", "E", "F", "G", "A", "B") assertScalesEqual(expected, Scale("C").interval("MMmMMMm")) } @Ignore @Test fun `major scale with sharps`() { val expected = listOf("G", "A", "B", "C", "D", "E", "F#") assertScalesEqual(expected, Scale("G").interval("MMmMMMm")) } @Ignore @Test fun `major scale with flats`() { val expected = listOf("F", "G", "A", "Bb", "C", "D", "E") assertScalesEqual(expected, Scale("F").interval("MMmMMMm")) } @Ignore @Test fun `minor scale with sharps`() { val expected = listOf("F#", "G#", "A", "B", "C#", "D", "E") assertScalesEqual(expected, Scale("f#").interval("MmMMmMM")) } @Ignore @Test fun `minor scale with flats`() { val expected = listOf("Bb", "C", "Db", "Eb", "F", "Gb", "Ab") assertScalesEqual(expected, Scale("bb").interval("MmMMmMM")) } @Ignore @Test fun `dorian mode`() { val expected = listOf("D", "E", "F", "G", "A", "B", "C") assertScalesEqual(expected, Scale("d").interval("MmMMMmM")) } @Ignore @Test fun `mixolydian mode`() { val expected = listOf("Eb", "F", "G", "Ab", "Bb", "C", "Db") assertScalesEqual(expected, Scale("Eb").interval("MMmMMmM")) } @Ignore @Test fun `lydian mode`() { val expected = listOf("A", "B", "C#", "D#", "E", "F#", "G#") assertScalesEqual(expected, Scale("a").interval("MMMmMMm")) } @Ignore @Test fun `phrygian mode`() { val expected = listOf("E", "F", "G", "A", "B", "C", "D") assertScalesEqual(expected, Scale("e").interval("mMMMmMM")) } @Ignore @Test fun `locrian mode`() { val expected = listOf("G", "Ab", "Bb", "C", "Db", "Eb", "F") assertScalesEqual(expected, Scale("g").interval("mMMmMMM")) } @Ignore @Test fun `harmonic minor`() { val expected = listOf("D", "E", "F", "G", "A", "Bb", "Db") assertScalesEqual(expected, Scale("d").interval("MmMMmAm")) } @Ignore @Test fun octatonic() { val expected = listOf("C", "D", "D#", "F", "F#", "G#", "A", "B") assertScalesEqual(expected, Scale("C").interval("MmMmMmMm")) } @Ignore @Test fun hexatonic() { val expected = listOf("Db", "Eb", "F", "G", "A", "B") assertScalesEqual(expected, Scale("Db").interval("MMMMMM")) } @Ignore @Test fun pentatonic() { val expected = listOf("A", "B", "C#", "E", "F#") assertScalesEqual(expected, Scale("A").interval("MMAMA")) } @Ignore @Test fun enigmatic() { val expected = listOf("G", "G#", "B", "C#", "D#", "F", "F#") assertScalesEqual(expected, Scale("G").interval("mAMMMmm")) } private fun assertScalesEqual(expected: List, actual: List) { asserter.assertTrue( { "Scales should be equal. Expected <$expected>, actual <$actual>" }, scalesAreEqual(expected, actual)) } private fun scalesAreEqual(expected: List, actual: List): Boolean { if (expected.size != actual.size) return false return expected.zip(actual, this::notesEqual).all { it } } // Few enough equal notes that we can just list them all fun notesEqual(left: String, right: String) = left == right || when(left) { // A# == Bb "A#" -> right == "Bb" "Bb" -> right == "A#" // C# == Db "C#" -> right == "Db" "Db" -> right == "C#" // D# == Eb "D#" -> right == "Eb" "Eb" -> right == "D#" // F# == Gb "F#" -> right == "Gb" "Gb" -> right == "F#" // G# == Ab "G#" -> right == "Ab" "Ab" -> right == "G#" else -> false } } ================================================ FILE: exercises/practice/scrabble-score/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "02863caf-f7d0-45bd-87f8-408e0030be55", "slug": "map", "title": "map", "blurb": "Use map lookups to return the answer.", "authors": [ "bobahop" ] }, { "uuid": "5481eb78-3c12-458f-b88c-3cf7632856e1", "slug": "when", "title": "when", "blurb": "Use when lookups to return the answer.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/scrabble-score/.approaches/introduction.md ================================================ # Introduction There are several ways to solve Scrabble Score. One approach is to use a [`when`][when] expression for looking up the letter scores. Another approach is to use a [`Map`][map] for looking up the letter scores. ## Approach: `when` ```kotlin object ScrabbleScore { private fun scoreLetter(c: Char) = when (c.uppercaseChar()) { 'A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T' -> 1 'D', 'G' -> 2 'B', 'C', 'M', 'P' -> 3 'F', 'H', 'V', 'W', 'Y' -> 4 'K' -> 5 'J', 'X' -> 8 'Q', 'Z' -> 10 else -> 0 } fun scoreWord(word: String) = word.sumOf { scoreLetter(it) } } ``` For more information, check the [`when` approach][approach-when]. ## Approach: `Map` ```kotlin object ScrabbleScore { private val compressedMap = mapOf( 1 to listOf('A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T'), 2 to listOf('D', 'G'), 3 to listOf('B', 'C', 'M', 'P'), 4 to listOf('F', 'H', 'V', 'W', 'Y'), 5 to listOf('K'), 8 to listOf('J', 'X'), 10 to listOf('Q', 'Z') ) private val lookup = mutableMapOf() init { compressedMap.forEach { entry -> entry.value.forEach { letter -> lookup.put(letter, entry.key) } } } fun scoreWord(word: String) = word.sumOf { lookup.getValue(it.uppercaseChar()) } } ``` For more information, check the [`Map` approach][approach-map]. ## Which approach to use? The `when` approach is succinct and reasonably performant. A `Map` lookup is fast, but it takes time to set up a `Map`, so for only a few lookups a `when` may be finished before the `Map` is built. Once the `Map` is built, if there are a lot of lookups, then the `Map` may finish all of them sooner than a `when`. [approach-when]: https://exercism.org/tracks/kotlin/exercises/scrabble-score/approaches/when [approach-map]: https://exercism.org/tracks/kotlin/exercises/scrabble-score/approaches/map [when]: https://kotlinlang.org/docs/control-flow.html#when-expression [map]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/ ================================================ FILE: exercises/practice/scrabble-score/.approaches/map/content.md ================================================ # `Map` ```kotlin object ScrabbleScore { private val compressedMap = mapOf( 1 to listOf('A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T'), 2 to listOf('D', 'G'), 3 to listOf('B', 'C', 'M', 'P'), 4 to listOf('F', 'H', 'V', 'W', 'Y'), 5 to listOf('K'), 8 to listOf('J', 'X'), 10 to listOf('Q', 'Z') ) private val lookup = mutableMapOf() init { compressedMap.forEach { entry -> entry.value.forEach { letter -> lookup.put(letter, entry.key) } } } fun scoreWord(word: String) = word.sumOf { lookup.getValue(it.uppercaseChar()) } } ``` An [object declaration][object] is used to define `ScrabbleScore` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `scoreWord` method. A [`private`][visibility] [`val`][variables] is defined to hold a `Map`. The `Map` is constructed with the [`mapOf`][mapOf] method, which is passed key/value [pairs][pair] made by the [`to`][to] keyword to associate the score key with its list of `Char` values. This is less tedious then typing the `Map` with a letter key and its score value for all of the letters. However, for an efficient lookup, we _want_ a letter key with its score value, so the [`mutableMapOf`][mutableMapOf] method is used to initialize the lookup map. Inside an [initializer block][constructors], two `forEach` loops are used for loading the lookup `Map` with the transformed key/values from the first `Map`. (If you have solved the `Etl` exercise, then this will be familiar to you.) Each key/value entry is passed into the [lambda][lambda] for the outer `forEach`. The inner `forEach` is called on the list of `Char` values for the entry. Each `Char` letter is passed into the lambda for the inner `forEach`, where the `put` method is used to create a new entry in the lookup `Map`, with the letter as the key and the score as the value. The `scoreWord` function is also a single-expression function, implemented with the `sumOf` [aggregate operation][aggregate-operation] on the input word. The [lambda][lambda] of `sumOf` uses the [`it`][it] keyword to refer to the single `Char` parameter for the lambda, and passes that to the [`getValue`][getvalue] method of the `Map` to look up the score for the letter. The function returns the result of calling `sumOf`, which is the sum of the scores for each of the characters in the word. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [visibility]: https://kotlinlang.org/docs/visibility-modifiers.html [variables]: https://kotlinlang.org/docs/basic-syntax.html#variables [mapOf]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map-of.html [pair]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/ [to]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html [mutableMapOf]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-map-of.html [constructors]: https://kotlinlang.org/docs/classes.html#constructors [single-expression-function]: https://kotlinlang.org/docs/functions.html#single-expression-functions [type-inference]: https://kotlinlang.org/spec/type-inference.html [aggregate-operation]: https://kotlinlang.org/docs/collection-aggregate.html [lambda]: https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions [it]: https://kotlinlang.org/docs/lambdas.html#it-implicit-name-of-a-single-parameter [getvalue]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/get-value.html ================================================ FILE: exercises/practice/scrabble-score/.approaches/map/snippet.txt ================================================ private val compressedMap = mapOf( 1 to listOf('A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T'), 2 to listOf('D', 'G'), 3 to listOf('B', 'C', 'M', 'P'), 4 to listOf('F', 'H', 'V', 'W', 'Y'), 5 to listOf('K'), 8 to listOf('J', 'X'), ================================================ FILE: exercises/practice/scrabble-score/.approaches/when/content.md ================================================ # `when` ```kotlin object ScrabbleScore { private fun scoreLetter(c: Char) = when (c.uppercaseChar()) { 'A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T' -> 1 'D', 'G' -> 2 'B', 'C', 'M', 'P' -> 3 'F', 'H', 'V', 'W', 'Y' -> 4 'K' -> 5 'J', 'X' -> 8 'Q', 'Z' -> 10 else -> 0 } fun scoreWord(word: String) = word.sumOf { scoreLetter(it) } } ``` An [object declaration][object] is used to define `ScrabbleScore` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `scoreWord` method. The [`private`][visibility] method for scoring the letter is implemented by a [`when`][when] expression. Although the function has multiple lines, it consists only of the one `when` expression, so it is defined using [single-expression function][single-expression-function] syntax, with the curly braces omitted and the return type [inferred][type-inference]. The `scoreWord` function is also a single-expression function, implemented with the `sumOf` [aggregate operation][aggregate-operation] on the input word. The [lambda][lambda] of `sumOf` uses the [`it`][it] keyword to refer to the single `Char` parameter for the lambda, and passes that to the function for scoring a letter. The function returns the result of calling `sumOf`, which is the sum of the scores for each of the characters in the word. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [visibility]: https://kotlinlang.org/docs/visibility-modifiers.html [when]: https://kotlinlang.org/docs/control-flow.html#when-expression [single-expression-function]: https://kotlinlang.org/docs/functions.html#single-expression-functions [type-inference]: https://kotlinlang.org/spec/type-inference.html [aggregate-operation]: https://kotlinlang.org/docs/collection-aggregate.html [lambda]: https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions [it]: https://kotlinlang.org/docs/lambdas.html#it-implicit-name-of-a-single-parameter ================================================ FILE: exercises/practice/scrabble-score/.approaches/when/snippet.txt ================================================ private fun scoreLetter(c: Char) = when (c.uppercaseChar()) { 'A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T' -> 1 'D', 'G' -> 2 'B', 'C', 'M', 'P' -> 3 'F', 'H', 'V', 'W', 'Y' -> 4 'K' -> 5 'J', 'X' -> 8 ================================================ FILE: exercises/practice/scrabble-score/.docs/instructions.md ================================================ # Instructions Your task is to compute a word's Scrabble score by summing the values of its letters. The letters are valued as follows: | Letter | Value | | ---------------------------- | ----- | | A, E, I, O, U, L, N, R, S, T | 1 | | D, G | 2 | | B, C, M, P | 3 | | F, H, V, W, Y | 4 | | K | 5 | | J, X | 8 | | Q, Z | 10 | For example, the word "cabbage" is worth 14 points: - 3 points for C - 1 point for A - 3 points for B - 3 points for B - 1 point for A - 2 points for G - 1 point for E ================================================ FILE: exercises/practice/scrabble-score/.docs/introduction.md ================================================ # Introduction [Scrabble][wikipedia] is a word game where players place letter tiles on a board to form words. Each letter has a value. A word's score is the sum of its letters' values. [wikipedia]: https://en.wikipedia.org/wiki/Scrabble ================================================ FILE: exercises/practice/scrabble-score/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ScrabbleScore.kt" ], "test": [ "src/test/kotlin/ScrabbleScoreTest.kt" ], "example": [ ".meta/src/reference/kotlin/ScrabbleScore.kt" ] }, "blurb": "Given a word, compute the Scrabble score for that word.", "source": "Inspired by the Extreme Startup game", "source_url": "https://github.com/rchatley/extreme_startup" } ================================================ FILE: exercises/practice/scrabble-score/.meta/src/reference/kotlin/ScrabbleScore.kt ================================================ object ScrabbleScore { private val scoreToLetters = mapOf(1 to "AEIOULNRST", 2 to "DG", 3 to "BCMP", 4 to "FHVWY", 5 to "K", 8 to "JX", 10 to "QZ").mapValues { it.value.toCharArray() } private val letterToScore = scoreToLetters.flatMap { entry -> entry.value.map { char -> Pair(char, entry.key) } }.toMap() fun scoreLetter(c: Char) = letterToScore[c.uppercaseChar()] ?: 0 fun scoreWord(word: String) = word.fold(0) { score, char -> score + scoreLetter(char) } } ================================================ FILE: exercises/practice/scrabble-score/.meta/tests.toml ================================================ [canonical-tests] # lowercase letter "f46cda29-1ca5-4ef2-bd45-388a767e3db2" = true # uppercase letter "f7794b49-f13e-45d1-a933-4e48459b2201" = true # valuable letter "eaba9c76-f9fa-49c9-a1b0-d1ba3a5b31fa" = true # short word "f3c8c94e-bb48-4da2-b09f-e832e103151e" = true # short, valuable word "71e3d8fa-900d-4548-930e-68e7067c4615" = true # medium word "d3088ad9-570c-4b51-8764-c75d5a430e99" = true # medium, valuable word "fa20c572-ad86-400a-8511-64512daac352" = true # long, mixed-case word "9336f0ba-9c2b-4fa0-bd1c-2e2d328cf967" = true # english-like word "1e34e2c3-e444-4ea7-b598-3c2b46fd2c10" = true # empty input "4efe3169-b3b6-4334-8bae-ff4ef24a7e4f" = true # entire alphabet available "3b305c1c-f260-4e15-a5b5-cb7d3ea7c3d7" = true ================================================ FILE: exercises/practice/scrabble-score/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/scrabble-score/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/scrabble-score/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/scrabble-score/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/scrabble-score/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/scrabble-score/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/scrabble-score/src/main/kotlin/ScrabbleScore.kt ================================================ object ScrabbleScore { fun scoreLetter(c: Char): Int { TODO("Implement this function to complete the task") } fun scoreWord(word: String): Int { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/scrabble-score/src/test/kotlin/ScrabbleScoreTest.kt ================================================ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.test.assertEquals @RunWith(Parameterized::class) class ScrabbleScoreTest(val input: String, val expectedOutput: Int) { companion object { @JvmStatic @Parameterized.Parameters(name = "{index}: scoreWord({0})={1}") fun data() = listOf( arrayOf("a", 1), arrayOf("A", 1), arrayOf("f", 4), arrayOf("at", 2), arrayOf("zoo", 12), arrayOf("street", 6), arrayOf("quirky", 22), arrayOf("OxyphenButazone", 41), arrayOf("pinata", 8), arrayOf("", 0), arrayOf("abcdefghijklmnopqrstuvwxyz", 87) ) } @Test fun test() { assertEquals(expectedOutput, ScrabbleScore.scoreWord(input)) } } ================================================ FILE: exercises/practice/secret-handshake/.docs/instructions.md ================================================ # Instructions Your task is to convert a number between 1 and 31 to a sequence of actions in the secret handshake. The sequence of actions is chosen by looking at the rightmost five digits of the number once it's been converted to binary. Start at the right-most digit and move left. The actions for each number place are: ```plaintext 00001 = wink 00010 = double blink 00100 = close your eyes 01000 = jump 10000 = Reverse the order of the operations in the secret handshake. ``` Let's use the number `9` as an example: - 9 in binary is `1001`. - The digit that is farthest to the right is 1, so the first action is `wink`. - Going left, the next digit is 0, so there is no double-blink. - Going left again, the next digit is 0, so you leave your eyes open. - Going left again, the next digit is 1, so you jump. That was the last digit, so the final code is: ```plaintext wink, jump ``` Given the number 26, which is `11010` in binary, we get the following actions: - double blink - jump - reverse actions The secret handshake for 26 is therefore: ```plaintext jump, double blink ``` ~~~~exercism/note If you aren't sure what binary is or how it works, check out [this binary tutorial][intro-to-binary]. [intro-to-binary]: https://medium.com/basecs/bits-bytes-building-with-binary-13cb4289aafa ~~~~ ================================================ FILE: exercises/practice/secret-handshake/.docs/introduction.md ================================================ # Introduction You are starting a secret coding club with some friends and friends-of-friends. Not everyone knows each other, so you and your friends have decided to create a secret handshake that you can use to recognize that someone is a member. You don't want anyone who isn't in the know to be able to crack the code. You've designed the code so that one person says a number between 1 and 31, and the other person turns it into a series of actions. ================================================ FILE: exercises/practice/secret-handshake/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/HandshakeCalculator.kt" ], "test": [ "src/test/kotlin/HandshakeCalculatorTest.kt" ], "example": [ ".meta/src/reference/kotlin/HandshakeCalculator.kt" ] }, "blurb": "Given a decimal number, convert it to the appropriate sequence of events for a secret handshake.", "source": "Bert, in Mary Poppins", "source_url": "https://www.imdb.com/title/tt0058331/quotes/?item=qt0437047" } ================================================ FILE: exercises/practice/secret-handshake/.meta/src/reference/kotlin/HandshakeCalculator.kt ================================================ object HandshakeCalculator { private const val REVERSE_SIGNALS_BIT_POSITION = 4 fun calculateHandshake(number: Int): List { val result = Signal.values().filter { signal -> isBitSet(signal.ordinal, number) } if (isBitSet(REVERSE_SIGNALS_BIT_POSITION, number)) { return result.asReversed() } else { return result } } private fun isBitSet(position: Int, number: Int): Boolean { return number shr position and 1 == 1 } } ================================================ FILE: exercises/practice/secret-handshake/.meta/src/reference/kotlin/Signal.kt ================================================ enum class Signal { WINK, DOUBLE_BLINK, CLOSE_YOUR_EYES, JUMP } ================================================ FILE: exercises/practice/secret-handshake/.meta/tests.toml ================================================ [canonical-tests] # wink for 1 "b8496fbd-6778-468c-8054-648d03c4bb23" = true # double blink for 10 "83ec6c58-81a9-4fd1-bfaf-0160514fc0e3" = true # close your eyes for 100 "0e20e466-3519-4134-8082-5639d85fef71" = true # jump for 1000 "b339ddbb-88b7-4b7d-9b19-4134030d9ac0" = true # combine two actions "40499fb4-e60c-43d7-8b98-0de3ca44e0eb" = true # reverse two actions "9730cdd5-ef27-494b-afd3-5c91ad6c3d9d" = true # reversing one action gives the same action "0b828205-51ca-45cd-90d5-f2506013f25f" = true # reversing no actions still gives no actions "9949e2ac-6c9c-4330-b685-2089ab28b05f" = true # all possible actions "23fdca98-676b-4848-970d-cfed7be39f81" = true # reverse all possible actions "ae8fe006-d910-4d6f-be00-54b7c3799e79" = true # do nothing for zero "3d36da37-b31f-4cdb-a396-d93a2ee1c4a5" = true ================================================ FILE: exercises/practice/secret-handshake/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/secret-handshake/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/secret-handshake/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/secret-handshake/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/secret-handshake/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/secret-handshake/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/secret-handshake/src/main/kotlin/HandshakeCalculator.kt ================================================ object HandshakeCalculator { fun calculateHandshake(number: Int): List { TODO("Implement the function to complete the task") } } ================================================ FILE: exercises/practice/secret-handshake/src/main/kotlin/Signal.kt ================================================ enum class Signal { WINK, DOUBLE_BLINK, CLOSE_YOUR_EYES, JUMP } ================================================ FILE: exercises/practice/secret-handshake/src/test/kotlin/HandshakeCalculatorTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class HandshakeCalculatorTest { @Test fun testThatInput1YieldsAWink() { assertEquals( listOf(Signal.WINK), HandshakeCalculator.calculateHandshake(1)) } @Ignore @Test fun testThatInput2YieldsADoubleBlink() { assertEquals( listOf(Signal.DOUBLE_BLINK), HandshakeCalculator.calculateHandshake(2)) } @Ignore @Test fun testThatInput4YieldsACloseYourEyes() { assertEquals( listOf(Signal.CLOSE_YOUR_EYES), HandshakeCalculator.calculateHandshake(4)) } @Ignore @Test fun testThatInput8YieldsAJump() { assertEquals( listOf(Signal.JUMP), HandshakeCalculator.calculateHandshake(8)) } @Ignore @Test fun testAnInputThatYieldsTwoActions() { assertEquals( listOf(Signal.WINK, Signal.DOUBLE_BLINK), HandshakeCalculator.calculateHandshake(3)) } @Ignore @Test fun testAnInputThatYieldsTwoReversedActions() { assertEquals( listOf(Signal.DOUBLE_BLINK, Signal.WINK), HandshakeCalculator.calculateHandshake(19)) } @Ignore @Test fun testReversingASingleActionYieldsTheSameAction() { assertEquals( listOf(Signal.JUMP), HandshakeCalculator.calculateHandshake(24)) } @Ignore @Test fun testReversingNoActionsYieldsNoActions() { assertEquals( emptyList(), HandshakeCalculator.calculateHandshake(16)) } @Ignore @Test fun testInputThatYieldsAllActions() { assertEquals( listOf(Signal.WINK, Signal.DOUBLE_BLINK, Signal.CLOSE_YOUR_EYES, Signal.JUMP), HandshakeCalculator.calculateHandshake(15)) } @Ignore @Test fun testInputThatYieldsAllActionsReversed() { assertEquals( listOf(Signal.JUMP, Signal.CLOSE_YOUR_EYES, Signal.DOUBLE_BLINK, Signal.WINK), HandshakeCalculator.calculateHandshake(31)) } @Ignore @Test fun testThatInput0YieldsNoActions() { assertEquals( emptyList(), HandshakeCalculator.calculateHandshake(0)) } @Ignore @Test fun testThatInputWithLower5BitsNotSetYieldsNoActions() { assertEquals( emptyList(), HandshakeCalculator.calculateHandshake(32)) } } ================================================ FILE: exercises/practice/series/.docs/instructions.md ================================================ # Instructions Given a string of digits, output all the contiguous substrings of length `n` in that string in the order that they appear. For example, the string "49142" has the following 3-digit series: - "491" - "914" - "142" And the following 4-digit series: - "4914" - "9142" And if you ask for a 6-digit series from a 5-digit string, you deserve whatever you get. Note that these series are only required to occupy _adjacent positions_ in the input; the digits need not be _numerically consecutive_. ================================================ FILE: exercises/practice/series/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "mikegehard", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Series.kt" ], "test": [ "src/test/kotlin/SeriesTest.kt" ], "example": [ ".meta/src/reference/kotlin/Series.kt" ] }, "blurb": "Given a string of digits, output all the contiguous substrings of length `n` in that string.", "source": "A subset of the Problem 8 at Project Euler", "source_url": "https://projecteuler.net/problem=8" } ================================================ FILE: exercises/practice/series/.meta/src/reference/kotlin/Series.kt ================================================ object Series { fun Char.toDigitValue() = this.code - '0'.code fun slices(n: Int, s: String): List> = when { (n > s.length) -> throw IllegalArgumentException("slice length cannot be greater than series length") (n == 0) -> throw IllegalArgumentException("slice length cannot be zero") (n < 0) -> throw IllegalArgumentException("slice length cannot be negative") (s == "") -> throw IllegalArgumentException("series cannot be empty") else -> s.dropLast(n - 1) .mapIndexed { index, _ -> s.subSequence(index, index + n).map { it.toDigitValue() } } } } ================================================ FILE: exercises/practice/series/.meta/tests.toml ================================================ [canonical-tests] # slices of one from one "7ae7a46a-d992-4c2a-9c15-a112d125ebad" = true # slices of one from two "3143b71d-f6a5-4221-aeae-619f906244d2" = true # slices of two "dbb68ff5-76c5-4ccd-895a-93dbec6d5805" = true # slices of two overlap "19bbea47-c987-4e11-a7d1-e103442adf86" = true # slices can include duplicates "8e17148d-ba0a-4007-a07f-d7f87015d84c" = true # slices of a long series "bd5b085e-f612-4f81-97a8-6314258278b0" = true # slice length is too large "6d235d85-46cf-4fae-9955-14b6efef27cd" = true # slice length cannot be zero "d34004ad-8765-4c09-8ba1-ada8ce776806" = true # slice length cannot be negative "10ab822d-8410-470a-a85d-23fbeb549e54" = true # empty series is invalid "c7ed0812-0e4b-4bf3-99c4-28cbbfc246a2" = true ================================================ FILE: exercises/practice/series/.meta/version ================================================ 1.0.0 ================================================ FILE: exercises/practice/series/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/series/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/series/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/series/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/series/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/series/src/main/kotlin/Series.kt ================================================ object Series { fun slices(n: Int, s: String): List> { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/series/src/test/kotlin/SeriesTest.kt ================================================ import kotlin.test.Test import kotlin.test.Ignore import kotlin.test.assertEquals class SeriesTest { @Test fun slicesOfOneFromOne() { assertEquals( listOf(listOf(1)), Series.slices(1, "1") ) } @Ignore @Test fun slicesOfOneFromTwo() { assertEquals( listOf(listOf(1), listOf(2)), Series.slices(1, "12") ) } @Ignore @Test fun slicesOfTwo() { assertEquals( listOf(listOf(3,5)), Series.slices(2, "35") ) } @Ignore @Test fun slicesOfTwoOverlap() { assertEquals( listOf(listOf(9,1), listOf(1,4), listOf(4,2)), Series.slices(2, "9142") ) } @Ignore @Test fun slicesCanIncludeDuplicates() { assertEquals( listOf(listOf(7,7,7), listOf(7,7,7), listOf(7,7,7), listOf(7,7,7)), Series.slices(3, "777777") ) } @Ignore @Test fun slicesOfALongSeries() { assertEquals( listOf(listOf(9,1,8,4,9), listOf(1,8,4,9,3), listOf(8,4,9,3,9), listOf(4,9,3,9,0), listOf(9,3,9,0,4), listOf(3,9,0,4,2), listOf(9,0,4,2,4), listOf(0,4,2,4,3)), Series.slices(5, "918493904243") ) } @Ignore @Test(expected = IllegalArgumentException::class) fun sliceLengthIsTooLarge() { Series.slices(4, "123") } @Ignore @Test(expected = IllegalArgumentException::class) fun sliceLengthCannotBeZero() { Series.slices(0, "123") } @Ignore @Test(expected = IllegalArgumentException::class) fun sliceLengthCannotBeNegative() { Series.slices(-2, "123") } @Ignore @Test(expected = IllegalArgumentException::class) fun emptySeriesIsInvalid() { Series.slices(1, "") Series.slices(1, "") } } ================================================ FILE: exercises/practice/sieve/.docs/instructions.md ================================================ # Instructions Your task is to create a program that implements the Sieve of Eratosthenes algorithm to find all prime numbers less than or equal to a given number. A prime number is a number larger than 1 that is only divisible by 1 and itself. For example, 2, 3, 5, 7, 11, and 13 are prime numbers. By contrast, 6 is _not_ a prime number as it not only divisible by 1 and itself, but also by 2 and 3. To use the Sieve of Eratosthenes, first, write out all the numbers from 2 up to and including your given number. Then, follow these steps: 1. Find the next unmarked number (skipping over marked numbers). This is a prime number. 2. Mark all the multiples of that prime number as **not** prime. Repeat the steps until you've gone through every number. At the end, all the unmarked numbers are prime. ~~~~exercism/note The Sieve of Eratosthenes marks off multiples of each prime using addition (repeatedly adding the prime) or multiplication (directly computing its multiples), rather than checking each number for divisibility. The tests don't check that you've implemented the algorithm, only that you've come up with the correct primes. ~~~~ ## Example Let's say you're finding the primes less than or equal to 10. - Write out 2, 3, 4, 5, 6, 7, 8, 9, 10, leaving them all unmarked. ```text 2 3 4 5 6 7 8 9 10 ``` - 2 is unmarked and is therefore a prime. Mark 4, 6, 8 and 10 as "not prime". ```text 2 3 [4] 5 [6] 7 [8] 9 [10] ↑ ``` - 3 is unmarked and is therefore a prime. Mark 6 and 9 as not prime _(marking 6 is optional - as it's already been marked)_. ```text 2 3 [4] 5 [6] 7 [8] [9] [10] ↑ ``` - 4 is marked as "not prime", so we skip over it. ```text 2 3 [4] 5 [6] 7 [8] [9] [10] ↑ ``` - 5 is unmarked and is therefore a prime. Mark 10 as not prime _(optional - as it's already been marked)_. ```text 2 3 [4] 5 [6] 7 [8] [9] [10] ↑ ``` - 6 is marked as "not prime", so we skip over it. ```text 2 3 [4] 5 [6] 7 [8] [9] [10] ↑ ``` - 7 is unmarked and is therefore a prime. ```text 2 3 [4] 5 [6] 7 [8] [9] [10] ↑ ``` - 8 is marked as "not prime", so we skip over it. ```text 2 3 [4] 5 [6] 7 [8] [9] [10] ↑ ``` - 9 is marked as "not prime", so we skip over it. ```text 2 3 [4] 5 [6] 7 [8] [9] [10] ↑ ``` - 10 is marked as "not prime", so we stop as there are no more numbers to check. ```text 2 3 [4] 5 [6] 7 [8] [9] [10] ↑ ``` You've examined all the numbers and found that 2, 3, 5, and 7 are still unmarked, meaning they're the primes less than or equal to 10. ================================================ FILE: exercises/practice/sieve/.docs/introduction.md ================================================ # Introduction You bought a big box of random computer parts at a garage sale. You've started putting the parts together to build custom computers. You want to test the performance of different combinations of parts, and decide to create your own benchmarking program to see how your computers compare. You choose the famous "Sieve of Eratosthenes" algorithm, an ancient algorithm, but one that should push your computers to the limits. ================================================ FILE: exercises/practice/sieve/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Sieve.kt" ], "test": [ "src/test/kotlin/SieveTest.kt" ], "example": [ ".meta/src/reference/kotlin/Sieve.kt" ] }, "blurb": "Use the Sieve of Eratosthenes to find all the primes from 2 up to a given number.", "source": "Sieve of Eratosthenes at Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes" } ================================================ FILE: exercises/practice/sieve/.meta/src/reference/kotlin/Sieve.kt ================================================ object Sieve { fun primesUpTo(upperBound: Int): List { val primes = mutableListOf() var candidates = (2..upperBound).toList() while (candidates.isNotEmpty()) { val prime = candidates[0] primes += prime candidates = candidates.filterIndexed { index, value -> index != 0 && value % prime != 0 } } return primes } } ================================================ FILE: exercises/practice/sieve/.meta/tests.toml ================================================ [canonical-tests] # no primes under two "88529125-c4ce-43cc-bb36-1eb4ddd7b44f" = true # find first prime "4afe9474-c705-4477-9923-840e1024cc2b" = true # find primes up to 10 "974945d8-8cd9-4f00-9463-7d813c7f17b7" = true # limit is prime "2e2417b7-3f3a-452a-8594-b9af08af6d82" = true # find primes up to 1000 "92102a05-4c7c-47de-9ed0-b7d5fcd00f21" = true ================================================ FILE: exercises/practice/sieve/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/sieve/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/sieve/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/sieve/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/sieve/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/sieve/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/sieve/src/main/kotlin/Sieve.kt ================================================ object Sieve { fun primesUpTo(upperBound: Int): List { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/sieve/src/test/kotlin/SieveTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class SieveTest { @Test fun noPrimesUnder2() { val expectedOutput = emptyList() assertEquals(expectedOutput, Sieve.primesUpTo(1)) } @Ignore @Test fun findFirstPrime() { val expectedOutput = listOf(2) assertEquals(expectedOutput, Sieve.primesUpTo(2)) } @Ignore @Test fun findPrimesUpTo10() { val expectedOutput = listOf(2, 3, 5, 7) assertEquals(expectedOutput, Sieve.primesUpTo(10)) } @Ignore @Test fun findPrimesUpTo1000() { val expectedOutput = listOf(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, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997) assertEquals(expectedOutput, Sieve.primesUpTo(1000)) } } ================================================ FILE: exercises/practice/simple-cipher/.docs/instructions.md ================================================ # Instructions Implement a simple shift cipher like Caesar and a more secure substitution cipher. ## Step 1 "If he had anything confidential to say, he wrote it in cipher, that is, by so changing the order of the letters of the alphabet, that not a word could be made out. If anyone wishes to decipher these, and get at their meaning, he must substitute the fourth letter of the alphabet, namely D, for A, and so with the others." —Suetonius, Life of Julius Caesar Ciphers are very straight-forward algorithms that allow us to render text less readable while still allowing easy deciphering. They are vulnerable to many forms of cryptanalysis, but Caesar was lucky that his enemies were not cryptanalysts. The Caesar cipher was used for some messages from Julius Caesar that were sent afield. Now Caesar knew that the cipher wasn't very good, but he had one ally in that respect: almost nobody could read well. So even being a couple letters off was sufficient so that people couldn't recognize the few words that they did know. Your task is to create a simple shift cipher like the Caesar cipher. This image is a great example of the Caesar cipher: ![Caesar cipher][img-caesar-cipher] For example: Giving "iamapandabear" as input to the encode function returns the cipher "ldpdsdqgdehdu". Obscure enough to keep our message secret in transit. When "ldpdsdqgdehdu" is put into the decode function it would return the original "iamapandabear" letting your friend read your original message. ## Step 2 Shift ciphers quickly cease to be useful when the opposition commander figures them out. So instead, let's try using a substitution cipher. Try amending the code to allow us to specify a key and use that for the shift distance. Here's an example: Given the key "aaaaaaaaaaaaaaaaaa", encoding the string "iamapandabear" would return the original "iamapandabear". Given the key "ddddddddddddddddd", encoding our string "iamapandabear" would return the obscured "ldpdsdqgdehdu" In the example above, we've set a = 0 for the key value. So when the plaintext is added to the key, we end up with the same message coming out. So "aaaa" is not an ideal key. But if we set the key to "dddd", we would get the same thing as the Caesar cipher. ## Step 3 The weakest link in any cipher is the human being. Let's make your substitution cipher a little more fault tolerant by providing a source of randomness and ensuring that the key contains only lowercase letters. If someone doesn't submit a key at all, generate a truly random key of at least 100 lowercase characters in length. ## Extensions Shift ciphers work by making the text slightly odd, but are vulnerable to frequency analysis. Substitution ciphers help that, but are still very vulnerable when the key is short or if spaces are preserved. Later on you'll see one solution to this problem in the exercise "crypto-square". If you want to go farther in this field, the questions begin to be about how we can exchange keys in a secure way. Take a look at [Diffie-Hellman on Wikipedia][dh] for one of the first implementations of this scheme. [img-caesar-cipher]: https://upload.wikimedia.org/wikipedia/commons/thumb/4/4a/Caesar_cipher_left_shift_of_3.svg/320px-Caesar_cipher_left_shift_of_3.svg.png [dh]: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange ================================================ FILE: exercises/practice/simple-cipher/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "mikegehard", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/SimpleCipher.kt" ], "test": [ "src/test/kotlin/SimpleCipherTest.kt" ], "example": [ ".meta/src/reference/kotlin/SimpleCipher.kt" ] }, "blurb": "Implement a simple shift cipher like Caesar and a more secure substitution cipher.", "source": "Substitution Cipher at Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Substitution_cipher" } ================================================ FILE: exercises/practice/simple-cipher/.meta/src/reference/kotlin/SimpleCipher.kt ================================================ import java.util.Random data class Cipher(val key: String) { constructor() : this(generateRandomKey()) init { require(key.matches(Regex("^[a-z]+$"))) { "Invalid key: $key" } } companion object { val random = Random() val alphabet = ('a'..'z').toList() private fun generateRandomKey() = generateSequence { alphabet[random.nextInt(alphabet.size)] }.take(100).joinToString("") } fun encode(s: String): String = s.mapIndexed { index, char -> encodeChar(char, index)}.joinToString("") fun decode(s: String): String = s.mapIndexed { index, char -> decodeChar(char, index)}.joinToString("") private fun encodeChar(character: Char, index: Int): Char { var alphaIdx = alphabet.indexOf(character) + alphabet.indexOf(key[index % key.length]) if(alphaIdx >= alphabet.size) alphaIdx -= alphabet.size return alphabet[alphaIdx] } private fun decodeChar(character: Char, index: Int): Char { var alphaIdx = alphabet.indexOf(character) - alphabet.indexOf(key[index % key.length]) if(alphaIdx < 0) alphaIdx += alphabet.size return alphabet[alphaIdx] } } ================================================ FILE: exercises/practice/simple-cipher/.meta/tests.toml ================================================ [canonical-tests] # Can encode "b8bdfbe1-bea3-41bb-a999-b41403f2b15d" = true # Can decode "3dff7f36-75db-46b4-ab70-644b3f38b81c" = true # Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method "8143c684-6df6-46ba-bd1f-dea8fcb5d265" = true # Key is made only of lowercase letters "defc0050-e87d-4840-85e4-51a1ab9dd6aa" = true # Can encode "565e5158-5b3b-41dd-b99d-33b9f413c39f" = true # Can decode "d44e4f6a-b8af-4e90-9d08-fd407e31e67b" = true # Is reversible. I.e., if you apply decode in a encoded result, you must see the same plaintext encode parameter as a result of the decode method "70a16473-7339-43df-902d-93408c69e9d1" = true # Can double shift encode "69a1458b-92a6-433a-a02d-7beac3ea91f9" = true # Can wrap on encode "21d207c1-98de-40aa-994f-86197ae230fb" = true # Can wrap on decode "a3d7a4d7-24a9-4de6-bdc4-a6614ced0cb3" = true # Can encode messages longer than the key "e31c9b8c-8eb6-45c9-a4b5-8344a36b9641" = true # Can decode messages longer than the key "93cfaae0-17da-4627-9a04-d6d1e1be52e3" = true ================================================ FILE: exercises/practice/simple-cipher/.meta/version ================================================ 2.0.0 ================================================ FILE: exercises/practice/simple-cipher/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/simple-cipher/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/simple-cipher/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/simple-cipher/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/simple-cipher/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/simple-cipher/src/main/kotlin/SimpleCipher.kt ================================================ data class Cipher(val todo: Nothing) { // TODO: Implement proper constructor fun encode(s: String): String { TODO("Implement this function to complete the task") } fun decode(s: String): String { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/simple-cipher/src/test/kotlin/IncorrectKeyCipherTest.kt ================================================ import org.junit.Test import org.junit.Ignore /** * Extra tests */ class IncorrectKeyCipherTest { @Test(expected = IllegalArgumentException::class) fun `key cannot consist of upper cased letters`() { Cipher("ABCDEF") } @Ignore @Test(expected = IllegalArgumentException::class) fun `key cannot contain upper cased letters`() { Cipher("abcdEFg") } @Ignore @Test(expected = IllegalArgumentException::class) fun `key cannot consist of digits`() { Cipher("12345") } @Ignore @Test(expected = IllegalArgumentException::class) fun `key cannot contain digits`() { Cipher("abcd345ef") } @Ignore @Test(expected = IllegalArgumentException::class) fun `key cannot be empty`() { Cipher("") } } ================================================ FILE: exercises/practice/simple-cipher/src/test/kotlin/RandomKeyCipherTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals import kotlin.test.assertTrue class RandomKeyCipherTest { @Test fun `can encode`() = with(Cipher()) { assertEquals(key.substring(0, 10), encode("aaaaaaaaaa")) } @Ignore @Test fun `can decode`() = with(Cipher()) { assertEquals("aaaaaaaaaa", decode(key.substring(0, 10))) } @Ignore @Test fun `key is made only of lowercase letters`() { assertTrue(Cipher().key.matches(Regex("[a-z]+"))) } @Ignore @Test fun `is reversible`() { val plainText = "abcdefghij" with(Cipher()) { assertEquals(plainText, decode(encode(plainText))) } } // extra tests @Ignore @Test fun `default key is of length 100`() { assertEquals(100, Cipher().key.length) } @Ignore @Test fun `two default generated keys differs`() { assertNotEquals(Cipher().key, Cipher().key) } } ================================================ FILE: exercises/practice/simple-cipher/src/test/kotlin/SimpleCipherTest.kt ================================================ import org.junit.runner.RunWith import org.junit.runners.Suite @RunWith(Suite::class) @Suite.SuiteClasses( RandomKeyCipherTest::class, IncorrectKeyCipherTest::class, SubstitutionCipherTest::class ) class SimpleCipherTest { } ================================================ FILE: exercises/practice/simple-cipher/src/test/kotlin/SubstitutionCipherTest.kt ================================================ import org.junit.Before import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class SubstitutionCipherTest { @Test fun `can encode`() = "abcdefghij".let { assertEquals(it, Cipher(it).encode("aaaaaaaaaa")) } @Ignore @Test fun `can decode`() = "abcdefghij".let { assertEquals("aaaaaaaaaa", Cipher(it).decode(it)) } @Ignore @Test fun `is reversible`() = with(Cipher("abcdefghij")) { assertEquals(key, decode(encode(key))) } @Ignore @Test fun `can double shift encode`() = "iamapandabear".let { assertEquals("qayaeaagaciai", Cipher(it).encode(it)) } @Ignore @Test fun `can wrap on encode`() = assertEquals("zabcdefghi", Cipher("abcdefghij").encode("zzzzzzzzzz")) @Ignore @Test fun `can wrap on decode`() = assertEquals("zzzzzzzzzz", Cipher("abcdefghij").decode("zabcdefghi")) @Ignore @Test fun `can encode messages longer than the key`() = assertEquals("iboaqcnecbfcr", Cipher("abc").encode("iamapandabear")) @Ignore @Test fun `can decode messages longer than the key`() = assertEquals("iamapandabear", Cipher("abc").decode("iboaqcnecbfcr")) // extra tests @Ignore @Test fun `keeps the given key`() = "abcdefghij".let { assertEquals(it, Cipher(it).key) } } ================================================ FILE: exercises/practice/space-age/.docs/instructions.md ================================================ # Instructions Given an age in seconds, calculate how old someone would be on a planet in our Solar System. One Earth year equals 365.25 Earth days, or 31,557,600 seconds. If you were told someone was 1,000,000,000 seconds old, their age would be 31.69 Earth-years. For the other planets, you have to account for their orbital period in Earth Years: | Planet | Orbital period in Earth Years | | ------- | ----------------------------- | | Mercury | 0.2408467 | | Venus | 0.61519726 | | Earth | 1.0 | | Mars | 1.8808158 | | Jupiter | 11.862615 | | Saturn | 29.447498 | | Uranus | 84.016846 | | Neptune | 164.79132 | ~~~~exercism/note The actual length of one complete orbit of the Earth around the sun is closer to 365.256 days (1 sidereal year). The Gregorian calendar has, on average, 365.2425 days. While not entirely accurate, 365.25 is the value used in this exercise. See [Year on Wikipedia][year] for more ways to measure a year. [year]: https://en.wikipedia.org/wiki/Year#Summary ~~~~ ================================================ FILE: exercises/practice/space-age/.docs/introduction.md ================================================ # Introduction The year is 2525 and you've just embarked on a journey to visit all planets in the Solar System (Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus and Neptune). The first stop is Mercury, where customs require you to fill out a form (bureaucracy is apparently _not_ Earth-specific). As you hand over the form to the customs officer, they scrutinize it and frown. "Do you _really_ expect me to believe you're just 50 years old? You must be closer to 200 years old!" Amused, you wait for the customs officer to start laughing, but they appear to be dead serious. You realize that you've entered your age in _Earth years_, but the officer expected it in _Mercury years_! As Mercury's orbital period around the sun is significantly shorter than Earth, you're actually a lot older in Mercury years. After some quick calculations, you're able to provide your age in Mercury Years. The customs officer smiles, satisfied, and waves you through. You make a mental note to pre-calculate your planet-specific age _before_ future customs checks, to avoid such mix-ups. ~~~~exercism/note If you're wondering why Pluto didn't make the cut, go watch [this YouTube video][pluto-video]. [pluto-video]: https://www.youtube.com/watch?v=Z_2gbGXzFbs ~~~~ ================================================ FILE: exercises/practice/space-age/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sanderploegsma", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/SpaceAge.kt" ], "test": [ "src/test/kotlin/SpaceAgeTest.kt" ], "example": [ ".meta/src/reference/kotlin/SpaceAge.kt" ] }, "blurb": "Given an age in seconds, calculate how old someone is in terms of a given planet's solar years.", "source": "Partially inspired by Chapter 1 in Chris Pine's online Learn to Program tutorial.", "source_url": "https://pine.fm/LearnToProgram/?Chapter=01" } ================================================ FILE: exercises/practice/space-age/.meta/src/reference/kotlin/SpaceAge.kt ================================================ class SpaceAge(private val seconds: Long) { companion object { const val EARTH_ORBITAL_PERIOD_IN_SECONDS = 31557600.0 private enum class Planet(val relativeOrbitalPeriod: Double) { EARTH(1.0), MERCURY(0.2408467), VENUS(0.61519726), MARS(1.8808158), JUPITER(11.862615), SATURN(29.447498), URANUS(84.016846), NEPTUNE(164.79132) } } fun onEarth() = calculateAge(Planet.EARTH) fun onMercury() = calculateAge(Planet.MERCURY) fun onVenus() = calculateAge(Planet.VENUS) fun onMars() = calculateAge(Planet.MARS) fun onJupiter() = calculateAge(Planet.JUPITER) fun onSaturn() = calculateAge(Planet.SATURN) fun onUranus() = calculateAge(Planet.URANUS) fun onNeptune() = calculateAge(Planet.NEPTUNE) private fun calculateAge(planet: Planet): Double = seconds / (EARTH_ORBITAL_PERIOD_IN_SECONDS * planet.relativeOrbitalPeriod) } ================================================ FILE: exercises/practice/space-age/.meta/tests.toml ================================================ [canonical-tests] # age on Earth "84f609af-5a91-4d68-90a3-9e32d8a5cd34" = true # age on Mercury "ca20c4e9-6054-458c-9312-79679ffab40b" = true # age on Venus "502c6529-fd1b-41d3-8fab-65e03082b024" = true # age on Mars "9ceadf5e-a0d5-4388-9d40-2c459227ceb8" = true # age on Jupiter "42927dc3-fe5e-4f76-a5b5-f737fc19bcde" = true # age on Saturn "8469b332-7837-4ada-b27c-00ee043ebcad" = true # age on Uranus "999354c1-76f8-4bb5-a672-f317b6436743" = true # age on Neptune "80096d30-a0d4-4449-903e-a381178355d8" = true ================================================ FILE: exercises/practice/space-age/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/space-age/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/space-age/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/space-age/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/space-age/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/space-age/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/space-age/src/main/kotlin/SpaceAge.kt ================================================ class SpaceAge { // TODO: Implement proper constructor fun onEarth(): Double = TODO("Implement this function to complete the task") fun onMercury(): Double = TODO("Implement this function to complete the task") fun onVenus(): Double = TODO("Implement this function to complete the task") fun onMars(): Double = TODO("Implement this function to complete the task") fun onJupiter(): Double = TODO("Implement this function to complete the task") fun onSaturn(): Double = TODO("Implement this function to complete the task") fun onUranus(): Double = TODO("Implement this function to complete the task") fun onNeptune(): Double = TODO("Implement this function to complete the task") } ================================================ FILE: exercises/practice/space-age/src/test/kotlin/SpaceAgeTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class SpaceAgeTest { @Test fun `age on Earth`() = assertYearsEqual(31.69, SpaceAge(1000000000).onEarth()) @Ignore @Test fun `age on Mercury`() = assertYearsEqual(280.88, SpaceAge(2134835688).onMercury()) @Ignore @Test fun `age on Venus`() = assertYearsEqual(9.78, SpaceAge(189839836).onVenus()) @Ignore @Test fun `age on Mars`() = assertYearsEqual(35.88, SpaceAge(2129871239).onMars()) @Ignore @Test fun `age on Jupiter`() = assertYearsEqual(2.41, SpaceAge(901876382).onJupiter()) @Ignore @Test fun `age on Saturn`() = assertYearsEqual(2.15, SpaceAge(2000000000).onSaturn()) @Ignore @Test fun `age on Uranus`() = assertYearsEqual(0.46, SpaceAge(1210123456).onUranus()) @Ignore @Test fun `age on Neptune`() = assertYearsEqual(0.35, SpaceAge(1821023456).onNeptune()) } private const val TOLERANCE = 0.01 private fun assertYearsEqual(expectedYears: Double, actualYears: Double) = assertEquals(expectedYears, actualYears, absoluteTolerance = TOLERANCE) ================================================ FILE: exercises/practice/spiral-matrix/.docs/instructions.md ================================================ # Instructions Your task is to return a square matrix of a given size. The matrix should be filled with natural numbers, starting from 1 in the top-left corner, increasing in an inward, clockwise spiral order, like these examples: ## Examples ### Spiral matrix of size 3 ```text 1 2 3 8 9 4 7 6 5 ``` ### Spiral matrix of size 4 ```text 1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 7 ``` ================================================ FILE: exercises/practice/spiral-matrix/.docs/introduction.md ================================================ # Introduction In a small village near an ancient forest, there was a legend of a hidden treasure buried deep within the woods. Despite numerous attempts, no one had ever succeeded in finding it. This was about to change, however, thanks to a young explorer named Elara. She had discovered an old document containing instructions on how to locate the treasure. Using these instructions, Elara was able to draw a map that revealed the path to the treasure. To her surprise, the path followed a peculiar clockwise spiral. It was no wonder no one had been able to find the treasure before! With the map in hand, Elara embarks on her journey to uncover the hidden treasure. ================================================ FILE: exercises/practice/spiral-matrix/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/SpiralMatrix.kt" ], "test": [ "src/test/kotlin/SpiralMatrixTest.kt" ], "example": [ ".meta/src/reference/kotlin/SpiralMatrix.kt" ] }, "blurb": "Given the size, return a square matrix of numbers in spiral order.", "source": "Reddit r/dailyprogrammer challenge #320 [Easy] Spiral Ascension.", "source_url": "https://web.archive.org/web/20230607064729/https://old.reddit.com/r/dailyprogrammer/comments/6i60lr/20170619_challenge_320_easy_spiral_ascension/" } ================================================ FILE: exercises/practice/spiral-matrix/.meta/src/reference/kotlin/SpiralMatrix.kt ================================================ import Direction.RIGHT import kotlin.math.pow enum class Direction(val dx: Int, val dy: Int) { UP ( 0, -1), RIGHT( 1, 0), DOWN ( 0, 1), LEFT (-1, 0); fun turnRight() = Direction.values()[(ordinal + 1) % Direction.values().size] } data class Coordinate(val x: Int, val y: Int) { fun step(direction: Direction) = copy(x + direction.dx, y + direction.dy) fun isWithinGridOfSize(size: Int) = x in 0 until size && y in 0 until size } object SpiralMatrix { fun ofSize(size: Int): Array { require(size >= 0) { "size must be a non-negative integer" } if (size == 0) return emptyArray() val result = Array(size) { IntArray(size) { 0 } } val entryCount = size.toDouble().pow(2.0).toInt() var coord = Coordinate(0, 0) var direction = RIGHT for (i in 0 until entryCount) { result[coord.y][coord.x] = i + 1 val maybeNextCoord = coord.step(direction) if (maybeNextCoord.isWithinGridOfSize(size) && result[maybeNextCoord.y][maybeNextCoord.x] == 0) { coord = maybeNextCoord } else { direction = direction.turnRight() coord = coord.step(direction) } } return result } } ================================================ FILE: exercises/practice/spiral-matrix/.meta/tests.toml ================================================ [canonical-tests] # empty spiral "8f584201-b446-4bc9-b132-811c8edd9040" = true # trivial spiral "e40ae5f3-e2c9-4639-8116-8a119d632ab2" = true # spiral of size 2 "cf05e42d-eb78-4098-a36e-cdaf0991bc48" = true # spiral of size 3 "1c475667-c896-4c23-82e2-e033929de939" = true # spiral of size 4 "05ccbc48-d891-44f5-9137-f4ce462a759d" = true # spiral of size 5 "f4d2165b-1738-4e0c-bed0-c459045ae50d" = true ================================================ FILE: exercises/practice/spiral-matrix/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/spiral-matrix/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/spiral-matrix/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/spiral-matrix/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/spiral-matrix/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/spiral-matrix/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/spiral-matrix/src/main/kotlin/SpiralMatrix.kt ================================================ object SpiralMatrix { fun ofSize(size: Int): Array { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/spiral-matrix/src/test/kotlin/SpiralMatrixTest.kt ================================================ import org.junit.Assert.assertArrayEquals import org.junit.Ignore import org.junit.Test class SpiralMatrixTest { @Test fun testEmptySpiral() { val expected = emptyArray() assertArrayEquals(expected, SpiralMatrix.ofSize(0)) } @Ignore @Test fun testTrivialSpiral() { val expected = arrayOf( intArrayOf(1) ) assertArrayEquals(expected, SpiralMatrix.ofSize(1)) } @Ignore @Test fun testSpiralOfSize2() { val expected = arrayOf( intArrayOf(1, 2), intArrayOf(4, 3) ) assertArrayEquals(expected, SpiralMatrix.ofSize(2)) } @Ignore @Test fun testSpiralOfSize3() { val expected = arrayOf( intArrayOf(1, 2, 3), intArrayOf(8, 9, 4), intArrayOf(7, 6, 5) ) assertArrayEquals(expected, SpiralMatrix.ofSize(3)) } @Ignore @Test fun testSpiralOfSize4() { val expected = arrayOf( intArrayOf( 1, 2, 3, 4), intArrayOf(12, 13, 14, 5), intArrayOf(11, 16, 15, 6), intArrayOf(10, 9, 8, 7) ) assertArrayEquals(expected, SpiralMatrix.ofSize(4)) } @Ignore @Test fun testSpiralOfSize5() { val expected = arrayOf( intArrayOf( 1, 2, 3, 4, 5), intArrayOf(16, 17, 18, 19, 6), intArrayOf(15, 24, 25, 20, 7), intArrayOf(14, 23, 22, 21, 8), intArrayOf(13, 12, 11, 10, 9) ) assertArrayEquals(expected, SpiralMatrix.ofSize(5)) } } ================================================ FILE: exercises/practice/strain/.docs/instructions.md ================================================ # Instructions Implement the `keep` and `discard` operation on collections. Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false. For example, given the collection of numbers: - 1, 2, 3, 4, 5 And the predicate: - is the number even? Then your keep operation should produce: - 2, 4 While your discard operation should produce: - 1, 3, 5 Note that the union of keep and discard is all the elements. The functions may be called `keep` and `discard`, or they may need different names in order to not clash with existing functions or concepts in your language. ## Restrictions Keep your hands off that filter/reject/whatchamacallit functionality provided by your standard library! Solve this one yourself using other basic tools instead. ================================================ FILE: exercises/practice/strain/.meta/config.json ================================================ { "blurb": "Implement the `keep` and `discard` operation on collections. Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false.", "authors": ["sdavids13"], "contributors": [ "dector", "eparovyshnaya", "jtigger", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": ["src/main/kotlin/Strain.kt"], "test": ["src/test/kotlin/StrainTest.kt"], "example": [".meta/src/reference/kotlin/Strain.kt"] }, "source": "Conversation with James Edward Gray II", "source_url": "https://twitter.com/jeg2" } ================================================ FILE: exercises/practice/strain/.meta/src/reference/kotlin/Strain.kt ================================================ object Strain { fun keep(collection: List, predicate: (T) -> Boolean): List { val filteredCollection = mutableListOf() collection.forEach { if (predicate(it)) filteredCollection.add(it) } return filteredCollection } fun discard(collection: List, predicate: (T) -> Boolean) = keep(collection) { value -> !predicate(value) } } ================================================ FILE: exercises/practice/strain/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/strain/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/strain/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/strain/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/strain/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/strain/src/main/kotlin/Strain.kt ================================================ object Strain { fun keep(collection: List, predicate: (T) -> Boolean): List { TODO("Implement this function to complete the task") } fun discard(collection: List, predicate: (T) -> Boolean): List { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/strain/src/test/kotlin/StrainTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class StrainTest { @Test fun emptyKeep() { val input = emptyList() val expectedOutput = emptyList() assertEquals(expectedOutput, Strain.keep(input, { it < 10 })) } @Ignore @Test fun keepEverything() { val input = listOf(1, 2, 3) val expectedOutput = listOf(1, 2, 3) assertEquals(expectedOutput, Strain.keep(input, { it < 10 })) } @Ignore @Test fun keepFirstAndLast() { val input = listOf(1, 2, 3) val expectedOutput = listOf(1, 3) assertEquals(expectedOutput, Strain.keep(input, { it % 2 != 0 })) } @Ignore @Test fun keepNeitherFirstNorLast() { val input = listOf(1, 2, 3, 4, 5) val expectedOutput = listOf(2, 4) assertEquals(expectedOutput, Strain.keep(input, { it % 2 == 0 })) } @Ignore @Test fun KeepStrings() { val words = "apple zebra banana zombies cherimoya zelot".split(" ") val expectedOutput = listOf("zebra", "zombies", "zelot") assertEquals(expectedOutput, Strain.keep(words, { it.startsWith("z") })) } @Ignore @Test fun keepArrays() { val actual = listOf( listOf(1, 2, 3), listOf(5, 5, 5), listOf(5, 1, 2), listOf(2, 1, 2), listOf(1, 5, 2), listOf(2, 2, 1), listOf(1, 2, 5)) val expectedOutput = listOf( listOf(5, 5, 5), listOf(5, 1, 2), listOf(1, 5, 2), listOf(1, 2, 5)) assertEquals(expectedOutput, Strain.keep(actual, { col -> col.contains(5) })) } @Ignore @Test fun emptyDiscard() { val input = emptyList() val expectedOutput = emptyList() assertEquals(expectedOutput, Strain.discard(input, { it < 10 })) } @Ignore @Test fun discardNothing() { val input = listOf(1, 2, 3) val expectedOutput = listOf(1, 2, 3) assertEquals(expectedOutput, Strain.discard(input, { it > 10 })) } @Ignore @Test fun discardFirstAndLast() { val input = listOf(1, 2, 3) val expectedOutput = listOf(2) assertEquals(expectedOutput, Strain.discard(input, { it % 2 != 0 })) } @Ignore @Test fun discardNeitherFirstNorLast() { val input = listOf(1, 2, 3, 4, 5) val expectedOutput = listOf(1, 3, 5) assertEquals(expectedOutput, Strain.discard(input, { it % 2 == 0 })) } @Ignore @Test fun discardStrings() { val words = "apple zebra banana zombies cherimoya zelot".split(" ") val expectedOutput = listOf("apple", "banana", "cherimoya") assertEquals(expectedOutput, Strain.discard(words, { it.startsWith("z") })) } @Ignore @Test fun discardArrays() { val actual = listOf( listOf(1, 2, 3), listOf(5, 5, 5), listOf(5, 1, 2), listOf(2, 1, 2), listOf(1, 5, 2), listOf(2, 2, 1), listOf(1, 2, 5)) val expectedOutput = listOf( listOf(1, 2, 3), listOf(2, 1, 2), listOf(2, 2, 1)) assertEquals(expectedOutput, Strain.discard(actual, { col -> col.contains(5) })) } } ================================================ FILE: exercises/practice/sublist/.docs/instructions.md ================================================ # Instructions Given any two lists `A` and `B`, determine if: - List `A` is equal to list `B`; or - List `A` contains list `B` (`A` is a superlist of `B`); or - List `A` is contained by list `B` (`A` is a sublist of `B`); or - None of the above is true, thus lists `A` and `B` are unequal Specifically, list `A` is equal to list `B` if both lists have the same values in the same order. List `A` is a superlist of `B` if `A` contains a contiguous sub-sequence of values equal to `B`. List `A` is a sublist of `B` if `B` contains a contiguous sub-sequence of values equal to `A`. Examples: - If `A = []` and `B = []` (both lists are empty), then `A` and `B` are equal - If `A = [1, 2, 3]` and `B = []`, then `A` is a superlist of `B` - If `A = []` and `B = [1, 2, 3]`, then `A` is a sublist of `B` - If `A = [1, 2, 3]` and `B = [1, 2, 3, 4, 5]`, then `A` is a sublist of `B` - If `A = [3, 4, 5]` and `B = [1, 2, 3, 4, 5]`, then `A` is a sublist of `B` - If `A = [3, 4]` and `B = [1, 2, 3, 4, 5]`, then `A` is a sublist of `B` - If `A = [1, 2, 3]` and `B = [1, 2, 3]`, then `A` and `B` are equal - If `A = [1, 2, 3, 4, 5]` and `B = [2, 3, 4]`, then `A` is a superlist of `B` - If `A = [1, 2, 4]` and `B = [1, 2, 3, 4, 5]`, then `A` and `B` are unequal - If `A = [1, 2, 3]` and `B = [1, 3, 2]`, then `A` and `B` are unequal ================================================ FILE: exercises/practice/sublist/.meta/config.json ================================================ { "authors": [ "stkent" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Sublist.kt" ], "test": [ "src/test/kotlin/SublistTest.kt" ], "example": [ ".meta/src/reference/kotlin/Sublist.kt" ] }, "blurb": "Write a function to determine if a list is a sublist of another list." } ================================================ FILE: exercises/practice/sublist/.meta/src/reference/kotlin/Relationship.kt ================================================ enum class Relationship { EQUAL, SUBLIST, SUPERLIST, UNEQUAL } ================================================ FILE: exercises/practice/sublist/.meta/src/reference/kotlin/Sublist.kt ================================================ fun List.relationshipTo(list: List): Relationship { if (this == list) return Relationship.EQUAL if (this.isSublist(list)) return Relationship.SUBLIST if (list.isSublist(this)) return Relationship.SUPERLIST return Relationship.UNEQUAL } private fun List.isSublist(list: List): Boolean { val listSize = list.size if (size > listSize) return false val numberOfSublistCandidates = listSize - size + 1 return (0 until numberOfSublistCandidates).any { startIndex -> list.subList(startIndex, startIndex + size) == this } } ================================================ FILE: exercises/practice/sublist/.meta/tests.toml ================================================ [canonical-tests] # empty lists "97319c93-ebc5-47ab-a022-02a1980e1d29" = true # empty list within non empty list "de27dbd4-df52-46fe-a336-30be58457382" = true # non empty list contains empty list "5487cfd1-bc7d-429f-ac6f-1177b857d4fb" = true # list equals itself "1f390b47-f6b2-4a93-bc23-858ba5dda9a6" = true # different lists "7ed2bfb2-922b-4363-ae75-f3a05e8274f5" = true # false start "3b8a2568-6144-4f06-b0a1-9d266b365341" = true # consecutive "dc39ed58-6311-4814-be30-05a64bc8d9b1" = true # sublist at start "d1270dab-a1ce-41aa-b29d-b3257241ac26" = true # sublist in middle "81f3d3f7-4f25-4ada-bcdc-897c403de1b6" = true # sublist at end "43bcae1e-a9cf-470e-923e-0946e04d8fdd" = true # at start of superlist "76cf99ed-0ff0-4b00-94af-4dfb43fe5caa" = true # in middle of superlist "b83989ec-8bdf-4655-95aa-9f38f3e357fd" = true # at end of superlist "26f9f7c3-6cf6-4610-984a-662f71f8689b" = true # first list missing element from second list "0a6db763-3588-416a-8f47-76b1cedde31e" = true # second list missing element from first list "83ffe6d8-a445-4a3c-8795-1e51a95e65c3" = true # order matters to a list "0d7ee7c1-0347-45c8-9ef5-b88db152b30b" = true # same digits but different numbers "5f47ce86-944e-40f9-9f31-6368aad70aa6" = true ================================================ FILE: exercises/practice/sublist/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/sublist/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/sublist/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/sublist/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/sublist/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/sublist/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/sublist/src/main/kotlin/Sublist.kt ================================================ enum class Relationship { EQUAL, SUBLIST, SUPERLIST, UNEQUAL } ================================================ FILE: exercises/practice/sublist/src/test/kotlin/SublistTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class SublistTest { @Test fun testThatTwoEmptyListsAreConsideredEqual() { assertEquals( Relationship.EQUAL, emptyList().relationshipTo(emptyList())) } @Ignore @Test fun testEmptyListIsSublistOfNonEmptyList() { assertEquals( Relationship.SUBLIST, emptyList().relationshipTo(listOf(1, 2, 3))) } @Ignore @Test fun testNonEmptyListIsSuperlistOfEmptyList() { assertEquals( Relationship.SUPERLIST, listOf('1', '2', '3').relationshipTo(emptyList())) } @Ignore @Test fun testListIsEqualToItself() { val anyList = listOf("1", "2", "3") assertEquals( Relationship.EQUAL, anyList.relationshipTo(anyList)) } @Ignore @Test fun testDifferentListsOfTheSameLengthAreUnequal() { assertEquals( Relationship.UNEQUAL, listOf(1, 2, 3).relationshipTo(listOf(2, 3, 4))) } @Ignore @Test fun testSublistCheckDoesNotAbortAfterFalseStart() { assertEquals( Relationship.SUBLIST, listOf('1', '2', '5').relationshipTo(listOf('0', '1', '2', '3', '1', '2', '5', '6'))) } @Ignore @Test fun testSublistCheckHandlesExtraneousRepeatsOfFirstEntry() { assertEquals( Relationship.SUBLIST, listOf("1", "1", "2").relationshipTo(listOf("0", "1", "1", "1", "2", "1", "2"))) } @Ignore @Test fun testSublistAtStart() { assertEquals( Relationship.SUBLIST, listOf(0, 1, 2).relationshipTo(listOf(0, 1, 2, 3, 4, 5))) } @Ignore @Test fun testSublistInMiddle() { assertEquals( Relationship.SUBLIST, listOf('2', '3', '4').relationshipTo(listOf('0', '1', '2', '3', '4', '5'))) } @Ignore @Test fun testSublistAtEnd() { assertEquals( Relationship.SUBLIST, listOf("3", "4", "5").relationshipTo(listOf("0", "1", "2", "3", "4", "5"))) } @Ignore @Test fun testAtStartOfSuperlist() { assertEquals( Relationship.SUPERLIST, listOf(0, 1, 2, 3, 4, 5).relationshipTo(listOf(0, 1, 2))) } @Ignore @Test fun testInMiddleOfSuperlist() { assertEquals( Relationship.SUPERLIST, listOf('0', '1', '2', '3', '4', '5').relationshipTo(listOf('2', '3'))) } @Ignore @Test fun testAtEndOfSuperlist() { assertEquals( Relationship.SUPERLIST, listOf("0", "1", "2", "3", "4", "5").relationshipTo(listOf("3", "4", "5"))) } @Ignore @Test fun testFirstListMissingElementFromSecondList() { assertEquals( Relationship.UNEQUAL, listOf(1, 3).relationshipTo(listOf(1, 2, 3))) } @Ignore @Test fun testSecondListMissingElementFromFirstList() { assertEquals( Relationship.UNEQUAL, listOf('1', '2', '3').relationshipTo(listOf('1', '3'))) } @Ignore @Test fun testThatListOrderingIsAccountedFor() { assertEquals( Relationship.UNEQUAL, listOf("1", "2", "3").relationshipTo(listOf("3", "2", "1"))) } @Ignore @Test fun testThatListsWithSameDigitsButDifferentNumbersAreUnequal() { assertEquals( Relationship.UNEQUAL, listOf(1, 0, 1).relationshipTo(listOf(10, 1))) } } ================================================ FILE: exercises/practice/sum-of-multiples/.docs/instructions.md ================================================ # Instructions Your task is to write the code that calculates the energy points that get awarded to players when they complete a level. The points awarded depend on two things: - The level (a number) that the player completed. - The base value of each magical item collected by the player during that level. The energy points are awarded according to the following rules: 1. For each magical item, take the base value and find all the multiples of that value that are less than the level number. 2. Combine the sets of numbers. 3. Remove any duplicates. 4. Calculate the sum of all the numbers that are left. Let's look at an example: **The player completed level 20 and found two magical items with base values of 3 and 5.** To calculate the energy points earned by the player, we need to find all the unique multiples of these base values that are less than level 20. - Multiples of 3 less than 20: `{3, 6, 9, 12, 15, 18}` - Multiples of 5 less than 20: `{5, 10, 15}` - Combine the sets and remove duplicates: `{3, 5, 6, 9, 10, 12, 15, 18}` - Sum the unique multiples: `3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 = 78` - Therefore, the player earns **78** energy points for completing level 20 and finding the two magical items with base values of 3 and 5. ================================================ FILE: exercises/practice/sum-of-multiples/.docs/introduction.md ================================================ # Introduction You work for a company that makes an online, fantasy-survival game. When a player finishes a level, they are awarded energy points. The amount of energy awarded depends on which magical items the player found while exploring that level. ================================================ FILE: exercises/practice/sum-of-multiples/.meta/config.json ================================================ { "authors": [ "nithia" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/SumOfMultiples.kt" ], "test": [ "src/test/kotlin/SumOfMultiplesTest.kt" ], "example": [ ".meta/src/reference/kotlin/SumOfMultiples.kt" ] }, "blurb": "Given a number, find the sum of all the multiples of particular numbers up to but not including that number.", "source": "A variation on Problem 1 at Project Euler", "source_url": "https://projecteuler.net/problem=1" } ================================================ FILE: exercises/practice/sum-of-multiples/.meta/src/reference/kotlin/SumOfMultiples.kt ================================================ object SumOfMultiples { fun sum(factors: Set, limit: Int) = with(factors.filter { it != 0 }) { (1 until limit).filter { x -> any { y -> x.isMultipleOf(y) } }.sum() } } fun Int.isMultipleOf(y: Int) = this % y == 0 ================================================ FILE: exercises/practice/sum-of-multiples/.meta/tests.toml ================================================ [canonical-tests] # no multiples within limit "54aaab5a-ce86-4edc-8b40-d3ab2400a279" = true # one factor has multiples within limit "361e4e50-c89b-4f60-95ef-5bc5c595490a" = true # more than one multiple within limit "e644e070-040e-4ae0-9910-93c69fc3f7ce" = true # more than one factor with multiples within limit "607d6eb9-535c-41ce-91b5-3a61da3fa57f" = true # each multiple is only counted once "f47e8209-c0c5-4786-b07b-dc273bf86b9b" = true # a much larger limit "28c4b267-c980-4054-93e9-07723db615ac" = true # three factors "09c4494d-ff2d-4e0f-8421-f5532821ee12" = true # factors not relatively prime "2d0d5faa-f177-4ad6-bde9-ebb865083751" = true # some pairs of factors relatively prime and some not "ece8f2e8-96aa-4166-bbb7-6ce71261e354" = true # one factor is a multiple of another "624fdade-6ffb-400e-8472-456a38c171c0" = true # much larger factors "949ee7eb-db51-479c-b5cb-4a22b40ac057" = true # all numbers are multiples of 1 "41093673-acbd-482c-ab80-d00a0cbedecd" = true # no factors means an empty sum "1730453b-baaa-438e-a9c2-d754497b2a76" = true # the only multiple of 0 is 0 "214a01e9-f4bf-45bb-80f1-1dce9fbb0310" = true # the factor 0 does not affect the sum of multiples of other factors "c423ae21-a0cb-4ec7-aeb1-32971af5b510" = true # solutions using include-exclude must extend to cardinality greater than 3 "17053ba9-112f-4ac0-aadb-0519dd836342" = true ================================================ FILE: exercises/practice/sum-of-multiples/.meta/version ================================================ 1.5.0 ================================================ FILE: exercises/practice/sum-of-multiples/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/sum-of-multiples/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/sum-of-multiples/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/sum-of-multiples/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/sum-of-multiples/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/sum-of-multiples/src/main/kotlin/SumOfMultiples.kt ================================================ object SumOfMultiples { fun sum(factors: Set, limit: Int): Int { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/sum-of-multiples/src/test/kotlin/SumOfMultiplesTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class SumOfMultiplesTest { @Test fun `no multiples within limit`() = assertEquals(0, SumOfMultiples.sum(setOf(3, 5), 1)) @Test @Ignore fun `one factor has multiples within limit`() = assertEquals(3, SumOfMultiples.sum(setOf(3, 5), 4)) @Test @Ignore fun `more than one multiple within limit`() = assertEquals(9, SumOfMultiples.sum(setOf(3), 7)) @Test @Ignore fun `more than one factor with multiples within limit`() = assertEquals(23, SumOfMultiples.sum(setOf(3, 5), 10)) @Test @Ignore fun `each multiple is only counted once`() = assertEquals(2318, SumOfMultiples.sum(setOf(3, 5), 100)) @Test @Ignore fun `much larger limit`() = assertEquals(233168, SumOfMultiples.sum(setOf(3, 5), 1000)) @Test @Ignore fun `three factors`() = assertEquals(51, SumOfMultiples.sum(setOf(7, 13, 17), 20)) @Test @Ignore fun `factors not relatively prime`() = assertEquals(30, SumOfMultiples.sum(setOf(4, 6), 15)) @Test @Ignore fun `some pairs of factors relatively prime and some not`() = assertEquals(4419, SumOfMultiples.sum(setOf(5, 6, 8), 150)) @Test @Ignore fun `one factor is a multiple of another`() = assertEquals(275, SumOfMultiples.sum(setOf(5, 25), 51)) @Test @Ignore fun `much larger factors`() = assertEquals(2203160, SumOfMultiples.sum(setOf(43, 47), 10000)) @Test @Ignore fun `all numbers are multiples of 1`() = assertEquals(4950, SumOfMultiples.sum(setOf(1), 100)) @Test @Ignore fun `no factors means an empty sum`() = assertEquals(0, SumOfMultiples.sum(emptySet(), 10000)) @Test @Ignore fun `the only multiple of 0 is 0`() = assertEquals(0, SumOfMultiples.sum(setOf(1), 1)) @Test @Ignore fun `the factor 0 does not affect the sum of multiples of other factors`() = assertEquals(3, SumOfMultiples.sum(setOf(3, 0), 4)) @Test @Ignore fun `include-exclude-based solutions must extend to cardinality greater than 3`() = assertEquals(39614537, SumOfMultiples.sum(setOf(2, 3, 5, 7, 11), 10000)) } ================================================ FILE: exercises/practice/transpose/.docs/instructions.md ================================================ # Instructions Given an input text output it transposed. Roughly explained, the transpose of a matrix: ```text ABC DEF ``` is given by: ```text AD BE CF ``` Rows become columns and columns become rows. See [transpose][]. If the input has rows of different lengths, this is to be solved as follows: - Pad to the left with spaces. - Don't pad to the right. Therefore, transposing this matrix: ```text ABC DE ``` results in: ```text AD BE C ``` And transposing: ```text AB DEF ``` results in: ```text AD BE F ``` In general, all characters from the input should also be present in the transposed output. That means that if a column in the input text contains only spaces on its bottom-most row(s), the corresponding output row should contain the spaces in its right-most column(s). [transpose]: https://en.wikipedia.org/wiki/Transpose ================================================ FILE: exercises/practice/transpose/.meta/config.json ================================================ { "authors": [ "lathspell" ], "files": { "solution": [ "src/main/kotlin/Transpose.kt" ], "test": [ "src/test/kotlin/TransposeTest.kt" ], "example": [ ".meta/src/reference/kotlin/Transpose.kt" ] }, "blurb": "Take input text and output it transposed.", "source": "Reddit r/dailyprogrammer challenge #270 [Easy].", "source_url": "https://web.archive.org/web/20230630051421/https://old.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text/" } ================================================ FILE: exercises/practice/transpose/.meta/src/reference/kotlin/Transpose.kt ================================================ object Transpose { fun transpose(input: List): List = (0 until (input.map { it.length }.maxOrNull() ?: 0)).map { x: Int -> input.indices.joinToString("") { y: Int -> if (x < input[y].length) { input[y][x].toString() } else { "°" } }.trimEnd('°').replace('°', ' ') } } ================================================ FILE: exercises/practice/transpose/.meta/tests.toml ================================================ [canonical-tests] # empty string "404b7262-c050-4df0-a2a2-0cb06cd6a821" = true # two characters in a row "a89ce8a3-c940-4703-a688-3ea39412fbcb" = true # two characters in a column "855bb6ae-4180-457c-abd0-ce489803ce98" = true # simple "5ceda1c0-f940-441c-a244-0ced197769c8" = true # single line "a54675dd-ae7d-4a58-a9c4-0c20e99a7c1f" = true # first line longer than second line "0dc2ec0b-549d-4047-aeeb-8029fec8d5c5" = true # second line longer than first line "984e2ec3-b3d3-4b53-8bd6-96f5ef404102" = true # mixed line length "eccd3784-45f0-4a3f-865a-360cb323d314" = true # square "85b96b3f-d00c-4f80-8ca2-c8a5c9216c2d" = true # rectangle "b9257625-7a53-4748-8863-e08e9d27071d" = true # triangle "b80badc9-057e-4543-bd07-ce1296a1ea2c" = true ================================================ FILE: exercises/practice/transpose/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/transpose/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/transpose/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/transpose/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/transpose/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/transpose/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/transpose/src/main/kotlin/Transpose.kt ================================================ object Transpose { fun transpose(input: List): List { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/transpose/src/test/kotlin/TransposeTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class TransposeTest { @Test fun `empty string`() { val lines = listOf() val expected = listOf() assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun `two characters in a row`() { val lines = listOf("A1") val expected = listOf("A", "1") assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun `two characters in a column`() { val lines = listOf("A", "1") val expected = listOf("A1") assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun simple() { val lines = listOf("ABC", "123") val expected = listOf("A1", "B2", "C3") assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun `single line`() { val lines = listOf("Single line.") val expected = listOf("S", "i", "n", "g", "l", "e", " ", "l", "i", "n", "e", ".") assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun `first line longer than second line`() { val lines = listOf("The fourth line.", "The fifth line.") val expected = listOf("TT", "hh", "ee", " ", "ff", "oi", "uf", "rt", "th", "h ", " l", "li", "in", "ne", "e.", ".") assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun `second line longer than first line`() { val lines = listOf("The first line.", "The second line.") val expected = listOf("TT", "hh", "ee", " ", "fs", "ie", "rc", "so", "tn", " d", "l ", "il", "ni", "en", ".e", " .") assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun `mixed line length`() { val lines = listOf("The longest line.", "A long line.", "A longer line.", "A line.") val expected = listOf("TAAA", "h ", "elll", " ooi", "lnnn", "ogge", "n e.", "glr", "ei ", "snl", "tei", " .n", "l e", "i .", "n", "e", ".") assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun square() { val lines = listOf("HEART", "EMBER", "ABUSE", "RESIN", "TREND") val expected = listOf("HEART", "EMBER", "ABUSE", "RESIN", "TREND") assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun rectangle() { val lines = listOf("FRACTURE", "OUTLINED", "BLOOMING", "SEPTETTE") val expected = listOf("FOBS", "RULE", "ATOP", "CLOT", "TIME", "UNIT", "RENT", "EDGE") assertEquals(expected, Transpose.transpose(lines)) } @Ignore @Test fun triangle() { val lines = listOf("T", "EE", "AAA", "SSSS", "EEEEE", "RRRRRR") val expected = listOf("TEASER", " EASER", " ASER", " SER", " ER", " R") assertEquals(expected, Transpose.transpose(lines)) } } ================================================ FILE: exercises/practice/triangle/.docs/instructions.md ================================================ # Instructions Determine if a triangle is equilateral, isosceles, or scalene. An _equilateral_ triangle has all three sides the same length. An _isosceles_ triangle has at least two sides the same length. (It is sometimes specified as having exactly two sides the same length, but for the purposes of this exercise we'll say at least two.) A _scalene_ triangle has all sides of different lengths. ## Note For a shape to be a triangle at all, all sides have to be of length > 0, and the sum of the lengths of any two sides must be greater than or equal to the length of the third side. In equations: Let `a`, `b`, and `c` be sides of the triangle. Then all three of the following expressions must be true: ```text a + b ≥ c b + c ≥ a a + c ≥ b ``` See [Triangle Inequality][triangle-inequality] [triangle-inequality]: https://en.wikipedia.org/wiki/Triangle_inequality ================================================ FILE: exercises/practice/triangle/.meta/config.json ================================================ { "authors": [ "nithia" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sdavids13", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Triangle.kt" ], "test": [ "src/test/kotlin/TriangleTest.kt" ], "example": [ ".meta/src/reference/kotlin/Triangle.kt" ] }, "blurb": "Determine if a triangle is equilateral, isosceles, or scalene.", "source": "The Ruby Koans triangle project, parts 1 & 2", "source_url": "https://web.archive.org/web/20220831105330/http://rubykoans.com" } ================================================ FILE: exercises/practice/triangle/.meta/src/reference/kotlin/Triangle.kt ================================================ class Triangle(val a: T, val b: T, val c: T) { init { require(a > 0 && b > 0 && c > 0) { "Sides must be > 0" } require(a + b >= c && b + c >= a && c + a >= b) { "Sides must satisfy triangle inequality" } } val isEquilateral = a == b && b == c val isIsosceles = a == b || b == c || c == a val isScalene = !isIsosceles private infix operator fun T.compareTo(other: T): Int = this.toDouble().compareTo(other.toDouble()) private infix operator fun T.plus(b: T): Double = this.toDouble().plus(b.toDouble()) } ================================================ FILE: exercises/practice/triangle/.meta/tests.toml ================================================ [canonical-tests] # all sides are equal "8b2c43ac-7257-43f9-b552-7631a91988af" = true # any side is unequal "33eb6f87-0498-4ccf-9573-7f8c3ce92b7b" = true # no sides are equal "c6585b7d-a8c0-4ad8-8a34-e21d36f7ad87" = true # all zero sides is not a triangle "16e8ceb0-eadb-46d1-b892-c50327479251" = true # sides may be floats "3022f537-b8e5-4cc1-8f12-fd775827a00c" = true # last two sides are equal "cbc612dc-d75a-4c1c-87fc-e2d5edd70b71" = true # first two sides are equal "e388ce93-f25e-4daf-b977-4b7ede992217" = true # first and last sides are equal "d2080b79-4523-4c3f-9d42-2da6e81ab30f" = true # equilateral triangles are also isosceles "8d71e185-2bd7-4841-b7e1-71689a5491d8" = true # no sides are equal "840ed5f8-366f-43c5-ac69-8f05e6f10bbb" = true # first triangle inequality violation "2eba0cfb-6c65-4c40-8146-30b608905eae" = true # second triangle inequality violation "278469cb-ac6b-41f0-81d4-66d9b828f8ac" = true # third triangle inequality violation "90efb0c7-72bb-4514-b320-3a3892e278ff" = true # sides may be floats "adb4ee20-532f-43dc-8d31-e9271b7ef2bc" = true # no sides are equal "e8b5f09c-ec2e-47c1-abec-f35095733afb" = true # all sides are equal "2510001f-b44d-4d18-9872-2303e7977dc1" = true # two sides are equal "c6e15a92-90d9-4fb3-90a2-eef64f8d3e1e" = true # may not violate triangle inequality "70ad5154-0033-48b7-af2c-b8d739cd9fdc" = true # sides may be floats "26d9d59d-f8f1-40d3-ad58-ae4d54123d7d" = true ================================================ FILE: exercises/practice/triangle/.meta/version ================================================ 1.2.1 ================================================ FILE: exercises/practice/triangle/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/triangle/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/triangle/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/triangle/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/triangle/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/triangle/src/main/kotlin/Triangle.kt ================================================ class Triangle(val a: T, val b: T, val c: T) { // TODO: Implement proper constructor val isEquilateral: Boolean = TODO("Implement this getter to complete the task") val isIsosceles: Boolean = TODO("Implement this getter to complete the task") val isScalene: Boolean = TODO("Implement this getter to complete the task") } ================================================ FILE: exercises/practice/triangle/src/test/kotlin/TriangleTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertFalse import kotlin.test.assertTrue class TriangleTest { @Test fun `equilateral - all sides are equal`() { assertTrue(Triangle(2, 2, 2).isEquilateral) } @Ignore @Test fun `equilateral - any side is unequal`() { assertFalse(Triangle(2, 3, 2).isEquilateral) } @Ignore @Test fun `equilateral - no sides are equal`() { assertFalse(Triangle(5, 4, 6).isEquilateral) } @Ignore @Test(expected = IllegalArgumentException::class) fun `equilateral - all zero sides is not a triangle`() { assertFalse(Triangle(0, 0, 0).isEquilateral) } @Ignore @Test fun `equilateral - sides may be floats`() { assertTrue(Triangle(0.5, 0.5, 0.5).isEquilateral) } @Ignore @Test fun `isosceles - last two sides are equal`() { assertTrue(Triangle(3, 4, 4).isIsosceles) } @Ignore @Test fun `isosceles - first two sides are equal`() { assertTrue(Triangle(4, 4, 3).isIsosceles) } @Ignore @Test fun `isosceles - first and last sides are equal`() { assertTrue(Triangle(4, 3, 4).isIsosceles) } @Ignore @Test fun `isosceles - equilateral triangles are also isosceles`() { assertTrue(Triangle(4, 4, 4).isIsosceles) } @Ignore @Test fun `isosceles - no sides are equal`() { assertFalse(Triangle(2, 3, 4).isIsosceles) } @Ignore @Test(expected = IllegalArgumentException::class) fun `triangle inequality violation - last is greater then sum of others `() { Triangle(1, 1, 3) } @Ignore @Test(expected = IllegalArgumentException::class) fun `triangle inequality violation - second is greater then sum of others `() { Triangle(1, 3, 1) } @Ignore @Test(expected = IllegalArgumentException::class) fun `triangle inequality violation - first is greater then sum of others `() { Triangle(3, 1, 1) } @Ignore @Test fun `isosceles - sides may be floats`() { assertTrue(Triangle(0.5, 0.4, 0.5).isIsosceles) } @Ignore @Test fun `scalene - no sides are equal`() { assertTrue(Triangle(5, 4, 6).isScalene) } @Ignore @Test fun `scalene - all sides are equal`() { assertFalse(Triangle(4, 4, 4).isScalene) } @Ignore @Test fun `scalene - two sides are equal`() { assertFalse(Triangle(4, 4, 3).isScalene) } @Ignore @Test(expected = IllegalArgumentException::class) fun `scalene - may not violate triangle inequality`() { Triangle(7, 3, 2) } @Ignore @Test fun `scalene - sides may be floats`() { assertTrue(Triangle(0.5, 0.4, 0.6).isScalene) } } ================================================ FILE: exercises/practice/two-fer/.docs/instructions.md ================================================ # Instructions Your task is to determine what you will say as you give away the extra cookie. If you know the person's name (e.g. if they're named Do-yun), then you will say: ```text One for Do-yun, one for me. ``` If you don't know the person's name, you will say _you_ instead. ```text One for you, one for me. ``` Here are some examples: | Name | Dialogue | | :----- | :-------------------------- | | Alice | One for Alice, one for me. | | Bohdan | One for Bohdan, one for me. | | | One for you, one for me. | | Zaphod | One for Zaphod, one for me. | ================================================ FILE: exercises/practice/two-fer/.docs/introduction.md ================================================ # Introduction In some English accents, when you say "two for" quickly, it sounds like "two fer". Two-for-one is a way of saying that if you buy one, you also get one for free. So the phrase "two-fer" often implies a two-for-one offer. Imagine a bakery that has a holiday offer where you can buy two cookies for the price of one ("two-fer one!"). You take the offer and (very generously) decide to give the extra cookie to someone else in the queue. ================================================ FILE: exercises/practice/two-fer/.meta/config.json ================================================ { "authors": [ "Mouzourides" ], "contributors": [ "dector", "eparovyshnaya", "lihofm", "mdowds", "sjwarner-bp", "SleeplessByte", "stkent", "sup95", "uzilan" ], "files": { "solution": [ "src/main/kotlin/TwoFer.kt" ], "test": [ "src/test/kotlin/TwoFerTest.kt" ], "example": [ ".meta/src/reference/kotlin/TwoFer.kt" ] }, "blurb": "Create a sentence of the form \"One for X, one for me.\".", "source_url": "https://github.com/exercism/problem-specifications/issues/757" } ================================================ FILE: exercises/practice/two-fer/.meta/src/reference/kotlin/TwoFer.kt ================================================ fun twofer(name: String = "you"): String { return "One for $name, one for me." } ================================================ FILE: exercises/practice/two-fer/.meta/tests.toml ================================================ [canonical-tests] # no name given "1cf3e15a-a3d7-4a87-aeb3-ba1b43bc8dce" = true # a name given "b4c6dbb8-b4fb-42c2-bafd-10785abe7709" = true # another name given "3549048d-1a6e-4653-9a79-b0bda163e8d5" = true ================================================ FILE: exercises/practice/two-fer/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/two-fer/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/two-fer/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/two-fer/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/two-fer/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/two-fer/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/two-fer/src/main/kotlin/TwoFer.kt ================================================ fun twofer(name: String): String { TODO("Implement the function to complete the task") } ================================================ FILE: exercises/practice/two-fer/src/test/kotlin/TwoFerTest.kt ================================================ import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class TwoFerTest { @Test fun noNameGiven() { assertEquals("One for you, one for me.", twofer()) } @Test @Ignore fun aNameGiven() { assertEquals("One for Alice, one for me.", twofer("Alice")) } @Test @Ignore fun anotherNameGiven() { assertEquals("One for Bob, one for me.", twofer("Bob")) } @Test @Ignore fun emptyStringGiven() { assertEquals("One for , one for me.", twofer("")) } } ================================================ FILE: exercises/practice/word-count/.approaches/config.json ================================================ { "introduction": { "authors": [ "bobahop" ] }, "approaches": [ { "uuid": "310ac3a8-5ef7-47c6-a2c9-5efc98a17d4a", "slug": "findall-groupingby-eachcount", "title": "findAll with groupingBy and eachCount", "blurb": "Use findAll with groupingBy and eachCount to return the answer.", "authors": [ "bobahop" ] } ] } ================================================ FILE: exercises/practice/word-count/.approaches/findall-groupingby-eachcount/content.md ================================================ # `findAll` with `groupingBy` and `eachCount` ```kotlin object WordCount { fun phrase(phrase: String): Map { return Regex("[a-z0-9]+(?:'[a-z]+)?") .findAll(phrase.lowercase()) .groupingBy { it.value } .eachCount() } } ``` An [object declaration][object] is used to define `WordCount` as essentially a [singleton][singleton] object instantiation of the class. This is sufficient, since there is no object state that needs to change with each call of the `phrase` method. A [regular expression][regex] pattern is defined to match the characters expected to be found in the words. At the time of writing, the valid characters are alphanumeric and the apostrophe. The pattern looks for one or more alphanumeric characters (`[a-z0-9]+`), either followed by an apostrophe and one or more alphabetic characters, or not (`(?:'[a-z]+)?`). The [`findAll`][findall] method is called on the `Regex` to match the words in the lowercased input to the pattern. The found words are passed to the [`groupingBy`][groupingby] method. The [lambda][lambda] of `groupingBy` uses the [`it`][it] keyword to refer to the single [`MatchResult`][matchresult] parameter for the lambda, and uses its [`value`][value] property for the value to be grouped by. Each group is then transformed into a `Map` by the [`eachCount`][eachcount] method, which creates a key/value pair for each word and its frequency as an entry for the `Map`. Finally, the `Map` is returned by the function. [object]: https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview [singleton]: https://en.wikipedia.org/wiki/Singleton_pattern [regex]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/ [findall]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/find-all.html [groupingby]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/grouping-by.html [lambda]: https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions [it]: https://kotlinlang.org/docs/lambdas.html#it-implicit-name-of-a-single-parameter [matchresult]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-match-result/ [value]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-match-result/value.html [eachcount]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/each-count.html ================================================ FILE: exercises/practice/word-count/.approaches/findall-groupingby-eachcount/snippet.txt ================================================ object WordCount { fun phrase(phrase: String): Map { return Regex("[a-z0-9]+(?:'[a-z]+)?") .findAll(phrase.lowercase()) .groupingBy { it.value } .eachCount() } } ================================================ FILE: exercises/practice/word-count/.approaches/introduction.md ================================================ # Introduction There are two main ways to solve Word Count. There are many variants of splitting the words on a more or less complex pattern, and that usually filter out blank/empty values. Another approach is to use a [regular expression][regex] pattern to find words. ## Approach: `findAll` with `groupingBy` and `eachCount` ```kotlin object WordCount { fun phrase(phrase: String): Map { return Regex("[a-z0-9]+(?:'[a-z]+)?") .findAll(phrase.lowercase()) .groupingBy { it.value } .eachCount() } } ``` For more information, check the [`findAll` with `groupingBy` and `eachCount` approach][approach-findall-groupingby-eachcount]. [approach-findall-groupingby-eachcount]: https://exercism.org/tracks/kotlin/exercises/word-count/approaches/findall-groupingby-eachcount [regex]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/ ================================================ FILE: exercises/practice/word-count/.docs/instructions.md ================================================ # Instructions Your task is to count how many times each word occurs in a subtitle of a drama. The subtitles from these dramas use only ASCII characters. The characters often speak in casual English, using contractions like _they're_ or _it's_. Though these contractions come from two words (e.g. _we are_), the contraction (_we're_) is considered a single word. Words can be separated by any form of punctuation (e.g. ":", "!", or "?") or whitespace (e.g. "\t", "\n", or " "). The only punctuation that does not separate words is the apostrophe in contractions. Numbers are considered words. If the subtitles say _It costs 100 dollars._ then _100_ will be its own word. Words are case insensitive. For example, the word _you_ occurs three times in the following sentence: > You come back, you hear me? DO YOU HEAR ME? The ordering of the word counts in the results doesn't matter. Here's an example that incorporates several of the elements discussed above: - simple words - contractions - numbers - case insensitive words - punctuation (including apostrophes) to separate words - different forms of whitespace to separate words `"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.` The mapping for this subtitle would be: ```text 123: 1 agent: 1 cried: 1 fled: 1 i: 1 password: 2 so: 1 special: 1 that's: 1 the: 2 ``` ================================================ FILE: exercises/practice/word-count/.docs/introduction.md ================================================ # Introduction You teach English as a foreign language to high school students. You've decided to base your entire curriculum on TV shows. You need to analyze which words are used, and how often they're repeated. This will let you choose the simplest shows to start with, and to gradually increase the difficulty as time passes. ================================================ FILE: exercises/practice/word-count/.meta/config.json ================================================ { "authors": [ "sdavids13" ], "contributors": [ "dector", "eparovyshnaya", "jtigger", "kytrinyx", "lihofm", "mdowds", "nithia", "sjwarner-bp", "SleeplessByte", "stkent", "uzilan" ], "files": { "solution": [ "src/main/kotlin/WordCount.kt" ], "test": [ "src/test/kotlin/WordCountTest.kt" ], "example": [ ".meta/src/reference/kotlin/WordCount.kt" ] }, "blurb": "Given a phrase, count the occurrences of each word in that phrase.", "source": "This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour." } ================================================ FILE: exercises/practice/word-count/.meta/src/reference/kotlin/WordCount.kt ================================================ object WordCount { fun phrase(phrase: String): Map { val withoutPunctuation = phrase.lowercase().replace(Regex("[^\\w']"), " ").trim() val words = withoutPunctuation.split(Regex("\\s+")) val unquotedWords = words.map { word -> word.trim('\'') } val groupedWords = unquotedWords.groupBy { w -> w } return groupedWords.mapValues { it.value.size } } } ================================================ FILE: exercises/practice/word-count/.meta/tests.toml ================================================ [canonical-tests] # count one word "61559d5f-2cad-48fb-af53-d3973a9ee9ef" = true # count one of each word "5abd53a3-1aed-43a4-a15a-29f88c09cbbd" = true # multiple occurrences of a word "2a3091e5-952e-4099-9fac-8f85d9655c0e" = true # handles cramped lists "e81877ae-d4da-4af4-931c-d923cd621ca6" = true # handles expanded lists "7349f682-9707-47c0-a9af-be56e1e7ff30" = true # ignore punctuation "a514a0f2-8589-4279-8892-887f76a14c82" = true # include numbers "d2e5cee6-d2ec-497b-bdc9-3ebe092ce55e" = true # normalize case "dac6bc6a-21ae-4954-945d-d7f716392dbf" = true # with apostrophes "4185a902-bdb0-4074-864c-f416e42a0f19" = true # with quotations "be72af2b-8afe-4337-b151-b297202e4a7b" = true # substrings from the beginning "8d6815fe-8a51-4a65-96f9-2fb3f6dc6ed6" = true # multiple spaces not detected as a word "c5f4ef26-f3f7-4725-b314-855c04fb4c13" = true # alternating word separators not detected as a word "50176e8a-fe8e-4f4c-b6b6-aa9cf8f20360" = true ================================================ FILE: exercises/practice/word-count/.meta/version ================================================ 1.4.0 ================================================ FILE: exercises/practice/word-count/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/word-count/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/word-count/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/word-count/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/word-count/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/word-count/src/main/kotlin/WordCount.kt ================================================ object WordCount { fun phrase(phrase: String): Map { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/word-count/src/test/kotlin/WordCountTest.kt ================================================ import org.junit.Test import org.junit.Ignore import kotlin.test.assertEquals class WordCountTest { @Test fun `one word`() = assertWordCountEqual( "word", "word" to 1 ) @Ignore @Test fun `one of each word`() = assertWordCountEqual( "one of each", "one" to 1, "of" to 1, "each" to 1 ) @Ignore @Test fun `multiple occurrences of a word`() = assertWordCountEqual( "one fish two fish red fish blue fish", "one" to 1, "fish" to 4, "two" to 1, "red" to 1, "blue" to 1 ) @Ignore @Test fun `cramped list`() = assertWordCountEqual( "one,two,three", "one" to 1, "two" to 1, "three" to 1 ) @Ignore @Test fun `expanded list`() = assertWordCountEqual( "one,\ntwo,\nthree", "one" to 1, "two" to 1, "three" to 1 ) @Ignore @Test fun `punctuation is ignored`() = assertWordCountEqual( "car: carpet as java: javascript!!&@\$%^&", "car" to 1, "carpet" to 1, "as" to 1, "java" to 1, "javascript" to 1 ) @Ignore @Test fun `numbers are allowed`() = assertWordCountEqual( "testing, 1, 2 testing", "testing" to 2, "1" to 1, "2" to 1 ) @Ignore @Test fun `case insensitive`() = assertWordCountEqual( "go Go GO Stop stop", "go" to 3, "stop" to 2 ) @Ignore @Test fun `apostrophes are allowed`() = assertWordCountEqual( "First: don't laugh. Then: don't cry.", "first" to 1, "don't" to 2, "laugh" to 1, "then" to 1, "cry" to 1 ) @Ignore @Test fun `quotations are allowed`() = assertWordCountEqual( "Joe can't tell between 'large' and large.", "joe" to 1, "can't" to 1, "tell" to 1, "between" to 1, "large" to 2, "and" to 1 ) @Ignore @Test fun `heading substring`() = assertWordCountEqual( "Joe can't tell between app, apple and a.", "joe" to 1, "can't" to 1, "tell" to 1, "between" to 1, "app" to 1, "apple" to 1, "and" to 1, "a" to 1 ) @Ignore @Test fun `multiple spaces`() = assertWordCountEqual( " multiple whitespaces", "multiple" to 1, "whitespaces" to 1 ) @Ignore @Test fun `various separators`() = assertWordCountEqual( ",\n,one,\n ,two \n 'three'", "one" to 1, "two" to 1, "three" to 1 ) } private fun assertWordCountEqual(phrase: String, vararg expectations: Pair) = assertEquals(expectations.toMap(), WordCount.phrase(phrase)) ================================================ FILE: exercises/practice/wordy/.docs/instructions.md ================================================ # Instructions Parse and evaluate simple math word problems returning the answer as an integer. ## Iteration 0 — Numbers Problems with no operations simply evaluate to the number given. > What is 5? Evaluates to 5. ## Iteration 1 — Addition Add two numbers together. > What is 5 plus 13? Evaluates to 18. Handle large numbers and negative numbers. ## Iteration 2 — Subtraction, Multiplication and Division Now, perform the other three operations. > What is 7 minus 5? 2 > What is 6 multiplied by 4? 24 > What is 25 divided by 5? 5 ## Iteration 3 — Multiple Operations Handle a set of operations, in sequence. Since these are verbal word problems, evaluate the expression from left-to-right, _ignoring the typical order of operations._ > What is 5 plus 13 plus 6? 24 > What is 3 plus 2 multiplied by 3? 15 (i.e. not 9) ## Iteration 4 — Errors The parser should reject: - Unsupported operations ("What is 52 cubed?") - Non-math questions ("Who is the President of the United States") - Word problems with invalid syntax ("What is 1 plus plus 2?") ================================================ FILE: exercises/practice/wordy/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Wordy.kt" ], "test": [ "src/test/kotlin/WordyTest.kt" ], "example": [ ".meta/src/reference/kotlin/Wordy.kt" ] }, "blurb": "Parse and evaluate simple math word problems returning the answer as an integer.", "source": "Inspired by one of the generated questions in the Extreme Startup game.", "source_url": "https://github.com/rchatley/extreme_startup" } ================================================ FILE: exercises/practice/wordy/.meta/src/reference/kotlin/Wordy.kt ================================================ import java.util.regex.Pattern import kotlin.math.pow object Wordy { private val startPattern = Pattern.compile("^What is (-?\\d+)(.*)\\?$") private val operandPattern = Pattern.compile("^ ([^-0-9]+) (-?\\d+)(.*)$") private val powerPattern = Pattern.compile("^ raised to the (-?\\d+)(st|nd|rd|th) power(.*)$") fun answer(input: String): Int { val startMatcher = startPattern.matcher(input) require(startMatcher.find()) val firstNumber = startMatcher.group(1).toInt() val rest = startMatcher.group(2) return answerRecursive(rest, firstNumber) } private fun answerRecursive(input: String, result: Int): Int { val operandMatcher = operandPattern.matcher(input) val powerMatcher = powerPattern.matcher(input) return when { powerMatcher.find() -> { val operand = powerMatcher.group(1).toInt() val rest = powerMatcher.group(3) answerRecursive(rest, result.toDouble().pow(operand.toDouble()).toInt()) } operandMatcher.find() -> { val operator = operandMatcher.group(1) val operand = operandMatcher.group(2).toInt() val rest = operandMatcher.group(3) when (operator) { "plus" -> answerRecursive(rest, result + operand) "minus" -> answerRecursive(rest, result - operand) "multiplied by" -> answerRecursive(rest, result * operand) "divided by" -> answerRecursive(rest, result / operand) else -> throw IllegalArgumentException("Unknown operator '$operator'!") } } input.isEmpty() -> result else -> throw IllegalArgumentException("Cannot parse '$input'!") } } } ================================================ FILE: exercises/practice/wordy/.meta/tests.toml ================================================ [canonical-tests] # just a number "88bf4b28-0de3-4883-93c7-db1b14aa806e" = true # addition "bb8c655c-cf42-4dfc-90e0-152fcfd8d4e0" = true # more addition "79e49e06-c5ae-40aa-a352-7a3a01f70015" = true # addition with negative numbers "b345dbe0-f733-44e1-863c-5ae3568f3803" = true # large addition "cd070f39-c4cc-45c4-97fb-1be5e5846f87" = true # subtraction "0d86474a-cd93-4649-a4fa-f6109a011191" = true # multiplication "30bc8395-5500-4712-a0cf-1d788a529be5" = true # division "34c36b08-8605-4217-bb57-9a01472c427f" = true # multiple additions "da6d2ce4-fb94-4d26-8f5f-b078adad0596" = true # addition and subtraction "7fd74c50-9911-4597-be09-8de7f2fea2bb" = true # multiple subtraction "b120ffd5-bad6-4e22-81c8-5512e8faf905" = true # subtraction then addition "4f4a5749-ef0c-4f60-841f-abcfaf05d2ae" = true # multiple multiplication "312d908c-f68f-42c9-aa75-961623cc033f" = true # addition and multiplication "38e33587-8940-4cc1-bc28-bfd7e3966276" = true # multiple division "3c854f97-9311-46e8-b574-92b60d17d394" = true # unknown operation "3ad3e433-8af7-41ec-aa9b-97b42ab49357" = true # Non math question "8a7e85a8-9e7b-4d46-868f-6d759f4648f8" = true # reject problem missing an operand "42d78b5f-dbd7-4cdb-8b30-00f794bb24cf" = true # reject problem with no operands or operators "c2c3cbfc-1a72-42f2-b597-246e617e66f5" = true # reject two operations in a row "4b3df66d-6ed5-4c95-a0a1-d38891fbdab6" = true # reject two numbers in a row "6abd7a50-75b4-4665-aa33-2030fd08bab1" = true # reject postfix notation "10a56c22-e0aa-405f-b1d2-c642d9c4c9de" = true # reject prefix notation "0035bc63-ac43-4bb5-ad6d-e8651b7d954e" = true ================================================ FILE: exercises/practice/wordy/.meta/version ================================================ 1.5.0 ================================================ FILE: exercises/practice/wordy/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/wordy/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/wordy/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/wordy/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/wordy/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/wordy/src/main/kotlin/Wordy.kt ================================================ object Wordy { fun answer(input: String): Int { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/wordy/src/test/kotlin/WordyTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class WordyTest { @Test fun `just a number`() = assertEquals(5, Wordy.answer("What is 5?")) @Ignore @Test fun addition() = assertEquals(2, Wordy.answer("What is 1 plus 1?")) @Ignore @Test fun `more addition`() = assertEquals(55, Wordy.answer("What is 53 plus 2?")) @Ignore @Test fun `addition with negative numbers`() = assertEquals(-11, Wordy.answer("What is -1 plus -10?")) @Ignore @Test fun `large addition`() = assertEquals(45801, Wordy.answer("What is 123 plus 45678?")) @Ignore @Test fun subtraction() = assertEquals(16, Wordy.answer("What is 4 minus -12?")) @Ignore @Test fun multiplication() = assertEquals(-75, Wordy.answer("What is -3 multiplied by 25?")) @Ignore @Test fun division() = assertEquals(-11, Wordy.answer("What is 33 divided by -3?")) @Ignore @Test fun `multiple additions`() = assertEquals(3, Wordy.answer("What is 1 plus 1 plus 1?")) @Ignore @Test fun `addition and subtraction`() = assertEquals(8, Wordy.answer("What is 1 plus 5 minus -2?")) @Ignore @Test fun `multiple subtraction`() = assertEquals(3, Wordy.answer("What is 20 minus 4 minus 13?")) @Ignore @Test fun `subtraction then addition`() = assertEquals(14, Wordy.answer("What is 17 minus 6 plus 3?")) @Ignore @Test fun `multiple multiplication`() = assertEquals(-12, Wordy.answer("What is 2 multiplied by -2 multiplied by 3?")) @Ignore @Test fun `addition and multiplication`() = assertEquals(-8, Wordy.answer("What is -3 plus 7 multiplied by -2?")) @Ignore @Test fun `multiple division`() = assertEquals(2, Wordy.answer("What is -12 divided by 2 divided by -3?")) @Ignore @Test(expected = Exception::class) fun `unknown operation`() = Wordy.answer("What is 52 cubed?").toUnit() @Ignore @Test(expected = Exception::class) fun `non math question`() = Wordy.answer("Who is the President of the United States?").toUnit() @Ignore @Test(expected = Exception::class) fun `reject problem missing an operand`() = Wordy.answer("What is 1 plus?").toUnit() @Ignore @Test(expected = Exception::class) fun `reject problem with no operands or operators`() = Wordy.answer("What is?").toUnit() @Ignore @Test(expected = Exception::class) fun `reject two operations in a row`() = Wordy.answer("What is 1 plus plus 2?").toUnit() @Ignore @Test(expected = Exception::class) fun `reject two numbers in a row`() = Wordy.answer("What is 1 plus 2 1?").toUnit() @Ignore @Test(expected = Exception::class) fun `reject postfix notation`() = Wordy.answer("What is 1 2 plus?").toUnit() @Ignore @Test(expected = Exception::class) fun `reject prefix notation`() = Wordy.answer("What is plus 1 2?").toUnit() // Additional tests for this track @Ignore @Test(expected = Exception::class) fun `missing operation`() = Wordy.answer("What is 2 2 minus 3?").toUnit() @Ignore @Test(expected = Exception::class) fun `missing number`() = Wordy.answer("What is 7 plus multiplied by -2?").toUnit() // Bonus Question @Ignore @Test fun power() = assertEquals(32, Wordy.answer("What is 2 raised to the 5th power?")) private fun Any.toUnit() = Unit // JUnit needs functions to return Unit } ================================================ FILE: exercises/practice/yacht/.docs/instructions.md ================================================ # Instructions Given five dice and a category, calculate the score of the dice for that category. ~~~~exercism/note You'll always be presented with five dice. Each dice's value will be between one and six inclusively. The dice may be unordered. ~~~~ ## Scores in Yacht | Category | Score | Description | Example | | --------------- | ---------------------- | ---------------------------------------- | ------------------- | | Ones | 1 × number of ones | Any combination | 1 1 1 4 5 scores 3 | | Twos | 2 × number of twos | Any combination | 2 2 3 4 5 scores 4 | | Threes | 3 × number of threes | Any combination | 3 3 3 3 3 scores 15 | | Fours | 4 × number of fours | Any combination | 1 2 3 3 5 scores 0 | | Fives | 5 × number of fives | Any combination | 5 1 5 2 5 scores 15 | | Sixes | 6 × number of sixes | Any combination | 2 3 4 5 6 scores 6 | | Full House | Total of the dice | Three of one number and two of another | 3 3 3 5 5 scores 19 | | Four of a Kind | Total of the four dice | At least four dice showing the same face | 4 4 4 4 6 scores 16 | | Little Straight | 30 points | 1-2-3-4-5 | 1 2 3 4 5 scores 30 | | Big Straight | 30 points | 2-3-4-5-6 | 2 3 4 5 6 scores 30 | | Choice | Sum of the dice | Any combination | 2 3 3 4 6 scores 18 | | Yacht | 50 points | All five dice showing the same face | 4 4 4 4 4 scores 50 | If the dice do **not** satisfy the requirements of a category, the score is zero. If, for example, _Four Of A Kind_ is entered in the _Yacht_ category, zero points are scored. A _Yacht_ scores zero if entered in the _Full House_ category. ================================================ FILE: exercises/practice/yacht/.docs/introduction.md ================================================ # Introduction Each year, something new is "all the rage" in your high school. This year it is a dice game: [Yacht][yacht]. The game of Yacht is from the same family as Poker Dice, Generala and particularly Yahtzee, of which it is a precursor. The game consists of twelve rounds. In each, five dice are rolled and the player chooses one of twelve categories. The chosen category is then used to score the throw of the dice. [yacht]: https://en.wikipedia.org/wiki/Yacht_(dice_game) ================================================ FILE: exercises/practice/yacht/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/Yacht.kt" ], "test": [ "src/test/kotlin/YachtTest.kt" ], "example": [ ".meta/src/reference/kotlin/Yacht.kt" ], "editor": [ "src/main/kotlin/YachtCategory.kt" ] }, "blurb": "Score a single throw of dice in the game Yacht.", "source": "James Kilfiger, using Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Yacht_(dice_game)" } ================================================ FILE: exercises/practice/yacht/.meta/src/reference/kotlin/Yacht.kt ================================================ import YachtCategory.* object Yacht { fun solve(category: YachtCategory, vararg dices: Int): Int = when (category) { YACHT -> if (dices.distinct().size == 1) 50 else 0 ONES -> dices.filter { it == 1 }.sum() TWOS -> dices.filter { it == 2 }.sum() THREES -> dices.filter { it == 3 }.sum() FOURS -> dices.filter { it == 4 }.sum() FIVES -> dices.filter { it == 5 }.sum() SIXES -> dices.filter { it == 6 }.sum() FULL_HOUSE -> { val counts = dices.groupBy { it }.map { it.key to it.value.count() }.sortedByDescending { it.second } if (counts.size >= 2 && counts[0].second >= 3 && counts[1].second >= 2) { counts[0].first * counts[0].second + counts[1].first * counts[1].second } else 0 } FOUR_OF_A_KIND -> dices.groupBy { it }.filter { it.value.size >= 4 }.keys.sumOf { it * 4 } LITTLE_STRAIGHT -> if ((1..5).all { dices.contains(it) }) 30 else 0 BIG_STRAIGHT -> if ((2..6).all { dices.contains(it) }) 30 else 0 CHOICE -> dices.sum() } } ================================================ FILE: exercises/practice/yacht/.meta/src/reference/kotlin/YachtCategory.kt ================================================ enum class YachtCategory { YACHT, ONES, TWOS, THREES, FOURS, FIVES, SIXES, FULL_HOUSE, FOUR_OF_A_KIND, LITTLE_STRAIGHT, BIG_STRAIGHT, CHOICE } ================================================ FILE: exercises/practice/yacht/.meta/tests.toml ================================================ [canonical-tests] # Yacht "3060e4a5-4063-4deb-a380-a630b43a84b6" = true # Not Yacht "15026df2-f567-482f-b4d5-5297d57769d9" = true # Ones "36b6af0c-ca06-4666-97de-5d31213957a4" = true # Ones, out of order "023a07c8-6c6e-44d0-bc17-efc5e1b8205a" = true # No ones "7189afac-cccd-4a74-8182-1cb1f374e496" = true # Twos "793c4292-dd14-49c4-9707-6d9c56cee725" = true # Fours "dc41bceb-d0c5-4634-a734-c01b4233a0c6" = true # Yacht counted as threes "f6125417-5c8a-4bca-bc5b-b4b76d0d28c8" = true # Yacht of 3s counted as fives "464fc809-96ed-46e4-acb8-d44e302e9726" = true # Sixes "e8a036e0-9d21-443a-8b5f-e15a9e19a761" = true # Full house two small, three big "51cb26db-6b24-49af-a9ff-12f53b252eea" = true # Full house three small, two big "1822ca9d-f235-4447-b430-2e8cfc448f0c" = true # Two pair is not a full house "b208a3fc-db2e-4363-a936-9e9a71e69c07" = true # Four of a kind is not a full house "b90209c3-5956-445b-8a0b-0ac8b906b1c2" = true # Yacht is not a full house "32a3f4ee-9142-4edf-ba70-6c0f96eb4b0c" = true # Four of a Kind "b286084d-0568-4460-844a-ba79d71d79c6" = true # Yacht can be scored as Four of a Kind "f25c0c90-5397-4732-9779-b1e9b5f612ca" = true # Full house is not Four of a Kind "9f8ef4f0-72bb-401a-a871-cbad39c9cb08" = true # Little Straight "b4743c82-1eb8-4a65-98f7-33ad126905cd" = true # Little Straight as Big Straight "7ac08422-41bf-459c-8187-a38a12d080bc" = true # Four in order but not a little straight "97bde8f7-9058-43ea-9de7-0bc3ed6d3002" = true # No pairs but not a little straight "cef35ff9-9c5e-4fd2-ae95-6e4af5e95a99" = true # Minimum is 1, maximum is 5, but not a little straight "fd785ad2-c060-4e45-81c6-ea2bbb781b9d" = true # Big Straight "35bd74a6-5cf6-431a-97a3-4f713663f467" = true # Big Straight as little straight "87c67e1e-3e87-4f3a-a9b1-62927822b250" = true # No pairs but not a big straight "c1fa0a3a-40ba-4153-a42d-32bc34d2521e" = true # Choice "207e7300-5d10-43e5-afdd-213e3ac8827d" = true # Yacht as choice "b524c0cf-32d2-4b40-8fb3-be3500f3f135" = true ================================================ FILE: exercises/practice/yacht/.meta/version ================================================ 1.2.0 ================================================ FILE: exercises/practice/yacht/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/yacht/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/yacht/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/yacht/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/yacht/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/yacht/src/main/kotlin/Yacht.kt ================================================ object Yacht { fun solve(category: YachtCategory, vararg dices: Int): Int { TODO("Implement this to complete the task") } } ================================================ FILE: exercises/practice/yacht/src/main/kotlin/YachtCategory.kt ================================================ enum class YachtCategory { YACHT, ONES, TWOS, THREES, FOURS, FIVES, SIXES, FULL_HOUSE, FOUR_OF_A_KIND, LITTLE_STRAIGHT, BIG_STRAIGHT, CHOICE } ================================================ FILE: exercises/practice/yacht/src/test/kotlin/YachtTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import YachtCategory.* class YachtTest { @Test fun yacht() = assertEquals(50, Yacht.solve(YACHT, 5, 5, 5, 5, 5)) @Ignore @Test fun `not yacht`() = assertEquals(0, Yacht.solve(YACHT, 1, 3, 3, 2, 5)) @Ignore @Test fun ones() = assertEquals(3, Yacht.solve(ONES, 1, 1, 1, 3, 5)) @Ignore @Test fun `ones out of order`() = assertEquals(3, Yacht.solve(ONES, 3, 1, 1, 5, 1)) @Ignore @Test fun `no ones`() = assertEquals(0, Yacht.solve(ONES, 4, 3, 6, 5, 5)) @Ignore @Test fun twos() = assertEquals(2, Yacht.solve(TWOS, 2, 3, 4, 5, 6)) @Ignore @Test fun fours() = assertEquals(8, Yacht.solve(FOURS, 1, 4, 1, 4, 1)) @Ignore @Test fun `yacht counted as threes`() = assertEquals(15, Yacht.solve(THREES, 3, 3, 3, 3, 3)) @Ignore @Test fun `yacht of threes counted as fives`() = assertEquals(0, Yacht.solve(FIVES, 3, 3, 3, 3, 3)) @Ignore @Test fun sixes() = assertEquals(6, Yacht.solve(SIXES, 2, 3, 4, 5, 6)) @Ignore @Test fun `full house two small three big`() = assertEquals(16, Yacht.solve(FULL_HOUSE, 2, 2, 4, 4, 4)) @Ignore @Test fun `full house three small two big`() = assertEquals(19, Yacht.solve(FULL_HOUSE, 5, 3, 3, 5, 3)) @Ignore @Test fun `two pair is not a full house`() = assertEquals(0, Yacht.solve(FULL_HOUSE, 2, 2, 4, 4, 5)) @Ignore @Test fun `four of a kind is not a full house`() = assertEquals(0, Yacht.solve(FULL_HOUSE, 1, 4, 4, 4, 4)) @Ignore @Test fun `yacht is not a full house`() = assertEquals(0, Yacht.solve(FULL_HOUSE, 2, 2, 2, 2, 2)) @Ignore @Test fun `four of a kind`() = assertEquals(24, Yacht.solve(FOUR_OF_A_KIND, 6, 6, 4, 6, 6)) @Ignore @Test fun `yacht can be scored as four of a kind`() = assertEquals(12, Yacht.solve(FOUR_OF_A_KIND, 3, 3, 3, 3, 3)) @Ignore @Test fun `full house is not four of a kind`() = assertEquals(0, Yacht.solve(FOUR_OF_A_KIND, 3, 3, 3, 5, 5)) @Ignore @Test fun `little straight`() = assertEquals(30, Yacht.solve(LITTLE_STRAIGHT, 3, 5, 4, 1, 2)) @Ignore @Test fun `little straight as big straight`() = assertEquals(0, Yacht.solve(BIG_STRAIGHT, 1, 2, 3, 4, 5)) @Ignore @Test fun `four in order but not a little straight`() = assertEquals(0, Yacht.solve(LITTLE_STRAIGHT, 1, 1, 2, 3, 4)) @Ignore @Test fun `no pairs but not a little straight`() = assertEquals(0, Yacht.solve(LITTLE_STRAIGHT, 1, 2, 3, 4, 6)) @Ignore @Test fun `minimum is 1 maximum is 5 but not a little straight`() = assertEquals(0, Yacht.solve(LITTLE_STRAIGHT, 1, 1, 3, 4, 5)) @Ignore @Test fun `big straight`() = assertEquals(30, Yacht.solve(BIG_STRAIGHT, 4, 6, 2, 5, 3)) @Ignore @Test fun `big straight as little straight`() = assertEquals(0, Yacht.solve(LITTLE_STRAIGHT, 6, 5, 4, 3, 2)) @Ignore @Test fun `no pairs but not a big straight`() = assertEquals(0, Yacht.solve(BIG_STRAIGHT, 6, 5, 4, 3, 1)) @Ignore @Test fun choice() = assertEquals(23, Yacht.solve(CHOICE, 3, 3, 5, 6, 6)) @Ignore @Test fun `yacht as choice`() = assertEquals(10, Yacht.solve(CHOICE, 2, 2, 2, 2, 2)) } ================================================ FILE: exercises/practice/zebra-puzzle/.docs/instructions.md ================================================ # Instructions Your task is to solve the Zebra Puzzle to find the answer to these two questions: - Which of the residents drinks water? - Who owns the zebra? ## Puzzle The following 15 statements are all known to be true: 1. There are five houses. 2. The Englishman lives in the red house. 3. The Spaniard owns the dog. 4. The person in the green house drinks coffee. 5. The Ukrainian drinks tea. 6. The green house is immediately to the right of the ivory house. 7. The snail owner likes to go dancing. 8. The person in the yellow house is a painter. 9. The person in the middle house drinks milk. 10. The Norwegian lives in the first house. 11. The person who enjoys reading lives in the house next to the person with the fox. 12. The painter's house is next to the house with the horse. 13. The person who plays football drinks orange juice. 14. The Japanese person plays chess. 15. The Norwegian lives next to the blue house. Additionally, each of the five houses is painted a different color, and their inhabitants are of different national extractions, own different pets, drink different beverages and engage in different hobbies. ~~~~exercism/note There are 24 billion (5!⁵ = 24,883,200,000) possible solutions, so try ruling out as many solutions as possible. ~~~~ ================================================ FILE: exercises/practice/zebra-puzzle/.docs/introduction.md ================================================ # Introduction The Zebra Puzzle is a famous logic puzzle in which there are five houses, each painted a different color. The houses have different inhabitants, who have different nationalities, own different pets, drink different beverages and enjoy different hobbies. To help you solve the puzzle, you're given 15 statements describing the solution. However, only by combining the information in _all_ statements will you be able to find the solution to the puzzle. ~~~~exercism/note The Zebra Puzzle is a [Constraint satisfaction problem (CSP)][constraint-satisfaction-problem]. In such a problem, you have a set of possible values and a set of constraints that limit which values are valid. Another well-known CSP is Sudoku. [constraint-satisfaction-problem]: https://en.wikipedia.org/wiki/Constraint_satisfaction_problem ~~~~ ================================================ FILE: exercises/practice/zebra-puzzle/.meta/config.json ================================================ { "authors": [ "lathspell" ], "contributors": [ "eparovyshnaya", "uzilan" ], "files": { "solution": [ "src/main/kotlin/ZebraPuzzle.kt" ], "test": [ "src/test/kotlin/ZebraPuzzleTest.kt" ], "example": [ ".meta/src/reference/kotlin/ZebraPuzzle.kt" ] }, "blurb": "Solve the zebra puzzle.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Zebra_Puzzle" } ================================================ FILE: exercises/practice/zebra-puzzle/.meta/src/reference/kotlin/HeapsPermutation.kt ================================================ /** Heap's Algorithm as seen on https://en.wikipedia.org/wiki/Heap%27s_algorithm. */ object HeapsPermutation { fun permute(vararg input: Int): Set = permute(input.size, input) private fun permute(k: Int, input: IntArray): Set = (0 until k).flatMap { i -> if (k == 1) { // Return a new object, as the received one is a mutable object which will be modified in swap() setOf(input.copyOf()) } else { val roundResults = permute(k - 1, input) if (isEven(k)) { swap(input, i, k - 1) } else { swap(input, 0, k - 1) } roundResults } }.toSet() private fun isEven(i: Int) = ((i % 2) == 0) private fun swap(input: IntArray, a: Int, b: Int) { val tmp = input[a] input[a] = input[b] input[b] = tmp } } ================================================ FILE: exercises/practice/zebra-puzzle/.meta/src/reference/kotlin/ZebraPuzzle.kt ================================================ class ZebraPuzzle { private var red = 0 private var green = 0 private var ivory = 0 private var yellow = 0 private var blue = 0 private var english = 0 private var spaniard = 0 private var ukrainian = 0 private var japanese = 0 private var norwegian = 0 private var coffee = 0 private var tea = 0 private var milk = 0 private var orangejuice = 0 private var water = 0 private var oldgold = 0 private var kools = 0 private var chesterfields = 0 private var luckystrike = 0 private var parliaments = 0 private var dog = 0 private var snails = 0 private var fox = 0 private var horse = 0 private var zebra = 0 private lateinit var nationalityNames: Map private lateinit var waterDrinker: String private lateinit var zebraOwner: String companion object { private const val FIRST = 1 private const val MIDDLE = 3 private fun isJustRightOf(neighbourA: Int, neighbourB: Int): Boolean { return neighbourA - 1 == neighbourB } private fun nextTo(neighbourA: Int, neighbourB: Int): Boolean { return isJustRightOf(neighbourA, neighbourB) || isJustRightOf(neighbourB, neighbourA) } private fun allHouseAssignmentPermutations() = HeapsPermutation.permute(1, 2, 3, 4, 5) } init { solve() } fun drinksWater() = waterDrinker fun ownsZebra() = zebraOwner private fun solve() { allHouseAssignmentPermutations().forEach { solveHouseColors(it) } } private fun solveHouseColors(permutation: IntArray) { red = permutation[0] green = permutation[1] ivory = permutation[2] yellow = permutation[3] blue = permutation[4] if (isJustRightOf(green, ivory)) { allHouseAssignmentPermutations().forEach { solveNationalities(it) } } } private fun solveNationalities(permutation: IntArray) { english = permutation[0] spaniard = permutation[1] ukrainian = permutation[2] japanese = permutation[3] norwegian = permutation[4] if (red == english && norwegian == FIRST && nextTo(norwegian, blue)) { // record names for later use nationalityNames = mapOf( english to "Englishman", spaniard to "Spaniard", ukrainian to "Ukrainian", japanese to "Japanese", norwegian to "Norwegian") allHouseAssignmentPermutations().forEach { solveBeverages(it) } } } private fun solveBeverages(permutation: IntArray) { coffee = permutation[0] tea = permutation[1] milk = permutation[2] orangejuice = permutation[3] water = permutation[4] if (coffee == green && ukrainian == tea && milk == MIDDLE) { allHouseAssignmentPermutations().forEach { solveCigars(it) } } } private fun solveCigars(permutation: IntArray) { oldgold = permutation[0] kools = permutation[1] chesterfields = permutation[2] luckystrike = permutation[3] parliaments = permutation[4] if (kools == yellow && luckystrike == orangejuice && japanese == parliaments) { allHouseAssignmentPermutations().forEach { solvePets(it) } } } private fun solvePets(permutation: IntArray) { dog = permutation[0] snails = permutation[1] fox = permutation[2] horse = permutation[3] zebra = permutation[4] if (spaniard == dog && oldgold == snails && nextTo(chesterfields, fox) && nextTo(kools, horse)) { waterDrinker = nationalityNames[water] ?: error("Water drinker not found!") zebraOwner = nationalityNames[zebra] ?: error("Zebra owner not found!") } } } ================================================ FILE: exercises/practice/zebra-puzzle/.meta/tests.toml ================================================ # This is an auto-generated file. # # Regenerating this file via `configlet sync` will: # - Recreate every `description` key/value pair # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) # - Preserve any other key/value pair # # As user-added comments (using the # character) will be removed when this file # is regenerated, comments can be added via a `comment` key. [16efb4e4-8ad7-4d5e-ba96-e5537b66fd42] description = "resident who drinks water" [084d5b8b-24e2-40e6-b008-c800da8cd257] description = "resident who owns zebra" ================================================ FILE: exercises/practice/zebra-puzzle/.meta/version ================================================ 1.1.0 ================================================ FILE: exercises/practice/zebra-puzzle/build.gradle.kts ================================================ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:4.13.2") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } ================================================ FILE: exercises/practice/zebra-puzzle/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: exercises/practice/zebra-puzzle/gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java if ! command -v java >/dev/null 2>&1 then die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. if ! command -v xargs >/dev/null 2>&1 then die "xargs is not available" fi # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: exercises/practice/zebra-puzzle/gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! set EXIT_CODE=%ERRORLEVEL% if %EXIT_CODE% equ 0 set EXIT_CODE=1 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: exercises/practice/zebra-puzzle/settings.gradle.kts ================================================ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/practice/zebra-puzzle/src/main/kotlin/ZebraPuzzle.kt ================================================ class ZebraPuzzle() { fun drinksWater(): String { TODO("Implement this function to complete the task") } fun ownsZebra(): String { TODO("Implement this function to complete the task") } } ================================================ FILE: exercises/practice/zebra-puzzle/src/test/kotlin/ZebraPuzzleTest.kt ================================================ import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class ZebraPuzzleTest { @Test fun `resident who drinks water`() = assertEquals("Norwegian", ZebraPuzzle().drinksWater()) @Ignore @Test fun `resident who owns zebra`() = assertEquals("Japanese", ZebraPuzzle().ownsZebra()) } ================================================ FILE: exercises/settings.gradle.kts ================================================ include( "concept:annalyns-infiltration", "concept:cars-assemble", "concept:log-levels", "concept:lucians-luscious-lasagna", "practice:accumulate", "practice:acronym", "practice:all-your-base", "practice:affine-cipher", "practice:allergies", "practice:anagram", "practice:armstrong-numbers", "practice:atbash-cipher", "practice:bank-account", "practice:beer-song", "practice:binary", "practice:binary-search", "practice:binary-search-tree", "practice:bob", "practice:bottle-song", "practice:bowling", "practice:change", "practice:circular-buffer", "practice:clock", "practice:collatz-conjecture", "practice:complex-numbers", "practice:crypto-square", "practice:custom-set", "practice:darts", "practice:diamond", "practice:difference-of-squares", "practice:diffie-hellman", "practice:dnd-character", "practice:dominoes", "practice:eliuds-eggs", "practice:etl", "practice:flatten-array", "practice:flower-field", "practice:forth", "practice:gigasecond", "practice:grade-school", "practice:grains", "practice:hamming", "practice:hello-world", "practice:hexadecimal", "practice:isbn-verifier", "practice:isogram", "practice:kindergarten-garden", "practice:knapsack", "practice:largest-series-product", "practice:leap", "practice:linked-list", "practice:list-ops", "practice:luhn", "practice:matching-brackets", "practice:matrix", "practice:meetup", "practice:minesweeper", "practice:nth-prime", "practice:nucleotide-count", "practice:pangram", "practice:pascals-triangle", "practice:perfect-numbers", "practice:phone-number", "practice:pig-latin", "practice:prime-factors", "practice:protein-translation", "practice:rail-fence-cipher", "practice:raindrops", "practice:react", "practice:resistor-color", "practice:resistor-color-duo", "practice:resistor-color-trio", "practice:reverse-string", "practice:rna-transcription", "practice:robot-name", "practice:robot-simulator", "practice:roman-numerals", "practice:rotational-cipher", "practice:run-length-encoding", "practice:saddle-points", "practice:say", "practice:scale-generator", "practice:scrabble-score", "practice:secret-handshake", "practice:series", "practice:sieve", "practice:simple-cipher", "practice:space-age", "practice:spiral-matrix", "practice:strain", "practice:sublist", "practice:sum-of-multiples", "practice:transpose", "practice:triangle", "practice:two-fer", "practice:word-count", "practice:wordy", "practice:yacht", "practice:zebra-puzzle", ) pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") } } } } ================================================ FILE: exercises/shared/.docs/help.md ================================================ # Help To get help if you're having trouble, you can use one of the following resources: - [Kotlin Documentation](https://kotlinlang.org/docs/reference/) - [Kotlin Forums](https://discuss.kotlinlang.org/) - [Kotlin Slack Channel](http://kotlinlang.slack.com/): [get invite here](http://slack.kotlinlang.org/) - [Stack Overflow](https://stackoverflow.com/questions/tagged/kotlin) - [Reddit Channel](https://www.reddit.com/r/kotlin) - [Twitter](https://twitter.com/kotlin) ================================================ FILE: exercises/shared/.docs/tests.md ================================================ # Tests Execute the tests with: ```bash $ gradlew test ``` > Use `gradlew.bat` if you're on Windows ## Skipped tests In the test suites all tests but the first have been skipped. Once you get a test passing, you can enable the next one by removing the `@Ignore` annotation. ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: gradlew ================================================ #!/bin/sh # # Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## # # Gradle start up script for POSIX generated by Gradle. # # Important for running: # # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is # noncompliant, but you have some other compliant shell such as ksh or # bash, then to run this script, type that shell name before the whole # command line, like: # # ksh Gradle # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # «${var#prefix}», «${var%suffix}», and «$( cmd )»; # * compound commands having a testable exit status, especially «case»; # * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # # (2) This script targets any POSIX shell, so it avoids extensions provided # by Bash, Ksh, etc; in particular arrays are avoided. # # The "traditional" practice of packing multiple parameters into a # space-separated string is a well documented source of bugs and security # problems, so this is (mostly) avoided, by progressively accumulating # options in "$@", and eventually passing that to Java. # # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; # see the in-line comments for details. # # There are tweaks for specific operating systems such as AIX, CygWin, # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. # ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link app_path=$0 # Need this for daisy-chained symlinks. while APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path [ -h "$app_path" ] do ls=$( ls -ld "$app_path" ) link=${ls#*' -> '} case $link in #( /*) app_path=$link ;; #( *) app_path=$APP_HOME$link ;; esac done APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum warn () { echo "$*" } >&2 die () { echo echo "$*" echo exit 1 } >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "$( uname )" in #( CYGWIN* ) cygwin=true ;; #( Darwin* ) darwin=true ;; #( MSYS* | MINGW* ) msys=true ;; #( NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD=$JAVA_HOME/jre/sh/java else JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi # Collect all arguments for the java command, stacking in reverse order: # * args from the command line # * the main class name # * -classpath # * -D...appname settings # * --module-path (only if needed) # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) # Now convert the arguments - kludge to limit ourselves to /bin/sh for arg do if case $arg in #( -*) false ;; # don't mess with options #( /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath [ -e "$t" ] ;; #( *) false ;; esac then arg=$( cygpath --path --ignore --mixed "$arg" ) fi # Roll the args list around exactly as many times as the number of # args, so each arg winds up back in the position where it started, but # possibly modified. # # NB: a `for` loop captures its iteration list before it begins, so # changing the positional parameters here affects neither the number of # iterations, nor the values presented in `arg`. shift # remove old arg set -- "$@" "$arg" # push replacement arg done fi # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in # double quotes to make sure that they get re-expanded; and # * put everything else in single quotes, so that it's not re-expanded. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ org.gradle.wrapper.GradleWrapperMain \ "$@" # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. # # In Bash we could simply go: # # readarray ARGS < <( xargs -n1 <<<"$var" ) && # set -- "${ARGS[@]}" "$@" # # but POSIX shell has neither arrays nor command substitution, so instead we # post-process each arg (as a line of input to sed) to backslash-escape any # character that might be a shell metacharacter, then use eval to reverse # that process (while maintaining the separation between arguments), and wrap # the whole thing up as a single "set" statement. # # This will of course break if any of these variables contains a newline or # an unmatched quote. # eval "set -- $( printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | xargs -n1 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | tr '\n' ' ' )" '"$@"' exec "$JAVACMD" "$@" ================================================ FILE: gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: reference/implementing-a-concept-exercise.md ================================================ # How to implement a Kotlin concept exercise ```diff ! WARNING! This document should be treated as a draft and will be actively changing. Sections that marked as WIP requires attention/rework from contributors. ``` This document describes the steps required to implement a concept exercise in any v3 track. **Please please please read the docs before starting.** Posting PRs without reading these docs will be a lot more frustrating for you during the review cycle, and exhaust Exercism's maintainers' time. So, before diving into the implementation, please read the following documents: - [The features of v3][docs-features-of-v3]. - [Rationale for v3][docs-rationale-for-v3]. - [What are concept exercise and how they are structured?][docs-concept-exercises] Please also watch the following video: - [The Anatomy of a Concept Exercise][anatomy-of-a-concept-exercise]. As this document is generic, the following placeholders are used: - ``: the name of the exercise in kebab-case (e.g. `calculator-conundrum`). - ``: the name of the exercise in PascalCase (e.g. `CalculatorConundrum`). - ``: the slug of one of the exercise's concepts in kebab-case (e.g. `anonymous-methods`). Before implementing the exercise, please make sure you have a good understanding of what the exercise should be teaching (and what not). This information can be found in the [exercise's GitHub issue](https://github.com/exercism/v3/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Atrack%2Fkotlin+Implement+new+concept+exercise+in%3Atitle). Any concept exercise in any v3 track requires the following files to be created:
languages
└── kotlin
    ├── concepts
    |   └── <concept-slug>
    |       ├── about.md
    |       └── links.json
    └── exercises
        └── concept
            └── <exercise-slug>
                ├── .docs
                |   ├── instructions.md
                |   ├── introduction.md
                |   ├── hints.md
                |   └── source.md (required if there are third-party sources)
                ├── .meta
                |   |── design.md
                |   |── config.json
                |   └── Exemplar.kt
                ├── src
                |   ├── main
                |   | 	└── kotlin
                |   | 		└── <ExerciseSlug>.kt
                |   └── test
                |    	└── kotlin
                |    		└── <ExerciseSlug>Test.kt
                └── gradle
                |	└── wrapper
                | 		├── gradle-wrapper.jar
                |		└── gradle-wrapper.properties
                ├── build.gradle.kts
                ├── gradlew
                └── gradlew.bat
## Step 1: Add code files The code files are track-specific and should be designed to help the student learn the exercise's concepts. The following Kotlin code files must be added (not necessarily in this order): - A stub implementation file (`src/main/kotlin/.kt`). - A file containing the test suite (`src/test/kotlin/.kt`). - An exemplar implementation file that passes all the tests (`meta/Example.kt`). What these files look like depends on your track. Note that some tracks might require more files in addition to the three files just mentioned. ## Step 2: Add documentation files How to create the files common to all tracks is described in the [how to implement a concept exercise document][how-to-implement-a-concept-exercise]. ## Step 3: Add analyzer (optional) ```diff ! WIP ignore this for now as we don't have proper analyzer yet ``` Some exercises could benefit from having an exercise-specific analyzer. If so, please check the track's analyzer document for details on how to do this. _Skip this step if you're not sure what to do._ ## Step 4: Add representation (optional) ```diff ! WIP ignore this for now as we don't have proper analyzer yet ``` Some exercises could benefit from having an custom representation as generated by the track's representer. If so, please check the track's representer document for details on how to do this. _Skip this step if you're not sure what to do._ ## Inspiration When implementing an exercise, it can be very useful to look at the exercises the track has already implemented. You can also check the exercise's [general concepts documents][reference] to see if other languages that have already an exercise for that concept. ## Help If you have any questions regarding implementing this exercise, please post them as comments in the exercise's GitHub issue. [reference]: ../reference/README.md [docs-concept-exercises]: https://github.com/exercism/v3/blob/main/docs/concept-exercises.md [docs-rationale-for-v3]: https://github.com/exercism/v3/blob/main/docs/rationale-for-v3.md [docs-features-of-v3]: https://github.com/exercism/v3/blob/main/docs/features-of-v3.md [anatomy-of-a-concept-exercise]: https://www.youtube.com/watch?v=gkbBqd7hPrA [how-to-implement-a-concept-exercise]: https://github.com/exercism/v3/blob/main/docs/maintainers/generic-how-to-implement-a-concept-exercise.md ================================================ FILE: scripts/canonical_data_check.sh ================================================ #!/usr/bin/env bash print_usage() { echo "Usage: ./canonical_data_check.sh -t path/to/track -s path/to/problem/specifications" } # Execution begins command -v jq >/dev/null 2>&1 || { echo >&2 "This script requires jq but it's not installed. Aborting." exit 1 } num_args=$# if [ $num_args -eq 0 ] then print_usage exit 0 fi path_to_track= path_to_problem_specifications= while getopts ":t:s:" option do case "$option" in "t") path_to_track="$OPTARG" ;; "s") path_to_problem_specifications="$OPTARG" ;; *) echo "Unrecognized option. Aborting." print_usage exit 1 ;; esac done if [ -z "$path_to_track" ] then echo "Path to track missing." print_usage exit 1 fi if [ -z "$path_to_problem_specifications" ] then echo "Path to problem specifications missing." print_usage exit 1 fi config_file_path="$path_to_track/config.json" if ! [ -f "$config_file_path" ] then echo "Config file not found at $config_file_path." exit 1 fi track_exercise_slugs=$(jq '.exercises[] | select(has("deprecated") | not) | .slug' $config_file_path | tr -d "\"") update_needed_count=0 for slug in $track_exercise_slugs do canonical_data_folder_path="$path_to_problem_specifications/exercises/$slug" if ! [ -d "$canonical_data_folder_path" ] then echo "Canonical data folder $canonical_data_folder_path not found. Aborting." exit 1 fi canonical_data_file_path="$canonical_data_folder_path/canonical-data.json" if ! [ -f "$canonical_data_file_path" ] then # echo "$slug: no canonical data found." continue fi canonical_data_version=$(jq '.version' $canonical_data_file_path | tr -d "\"") track_exercise_version_file_path="$path_to_track/exercises/$slug/.meta/version" if ! [ -f "$track_exercise_version_file_path" ] then echo "$slug: needs update or version file (v$canonical_data_version)." update_needed_count=$((update_needed_count + 1)) continue fi track_data_version=$(cat $track_exercise_version_file_path) if [ "$track_data_version" = "$canonical_data_version" ] then # echo "$slug: up-to-date." continue else update_needed_count=$((update_needed_count + 1)) echo "$slug: needs update (v$track_data_version -> v$canonical_data_version)." fi done if [ $update_needed_count -eq 0 ] then echo "All exercises are up to date!" fi ================================================ FILE: scripts/fix_exercises_symlinks.sh ================================================ #!/usr/bin/env bash # This script looks through each exercise folder to identify symlinked files in the .meta folder and replaces the files # with actual symlinks. This is mainly to fix weird behavior with Git and symlinks. grep -R -e '^\.\./\.\.' exercises | cut -d: -f1 - | while IFS= read -r file do dir=$(dirname "$file") filename=$(basename "$file") target=$(cat "$file") echo "Replacing ${file} with symlink to ${target}." pushd "$dir" || continue rm -f "$filename" ln -s "$target" "$filename" popd || continue unset dir filename done ================================================ FILE: scripts/updateGradleFilesFromTemplate.kts ================================================ #!/usr/bin/env kscript import java.io.File fun updateGradleFiles() { val exerciseDirs = File("exercises").listFiles() .filter { it.isDirectory } .flatMap { it.listFiles().filter { it.resolve("src/main/kotlin").exists() } } val filesToCopy = listOf( "build.gradle.kts", "settings.gradle.kts", "gradle/", "gradlew", "gradlew.bat" ) val executables = listOf( "gradlew", "gradlew.bat" ) exerciseDirs.forEach { dir -> println(dir.name) dir.resolve("build.gradle") .takeIf { it.exists() } ?.delete() val templateDir = File("_template") filesToCopy.forEach { file -> val src = templateDir.resolve(file) val dest = dir.resolve(file) src.copyRecursively(dest, overwrite = true) if (file in executables) { dest.setExecutable(true) } } } } updateGradleFiles() ================================================ FILE: scripts/updateTemplateBuildFile.kts ================================================ #!/usr/bin/env kscript import java.io.File fun updateTemplate() { val versions = object { val kotlin = "1.6.0" val junit4 = "4.13.2" } File("_template").resolve("build.gradle.kts").writeText( """ import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") } repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-jdk8")) testImplementation("junit:junit:${versions.junit4}") testImplementation(kotlin("test-junit")) } tasks.withType { testLogging { exceptionFormat = TestExceptionFormat.FULL events("passed", "failed", "skipped") } } """.trimIndent() ) File("_template").resolve("settings.gradle.kts").writeText( """ pluginManagement { repositories { mavenCentral() gradlePluginPortal() } resolutionStrategy { eachPlugin { when (requested.id.id) { "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}") } } } } """.trimIndent() ) } updateTemplate()