├── img └── .keep ├── docs ├── LEARNING.md ├── SNIPPET.txt ├── RESOURCES.md ├── ABOUT.md └── config.json ├── testlib └── CMakeLists.txt ├── exercises ├── practice │ ├── leap │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── leap.f90 │ │ ├── .meta │ │ │ ├── example.f90 │ │ │ ├── config.json │ │ │ └── tests.toml │ │ └── leap_test.f90 │ ├── triangle │ │ ├── .docs │ │ │ ├── hints.md │ │ │ └── instructions.md │ │ ├── .meta │ │ │ └── config.json │ │ └── triangle.f90 │ ├── grains │ │ ├── .docs │ │ │ ├── hints.md │ │ │ ├── introduction.md │ │ │ └── instructions.md │ │ ├── grains.f90 │ │ ├── .meta │ │ │ ├── example.f90 │ │ │ ├── config.json │ │ │ └── tests.toml │ │ └── grains_test.f90 │ ├── raindrops │ │ ├── .docs │ │ │ ├── introduction.md │ │ │ └── instructions.md │ │ ├── raindrops.f90 │ │ └── .meta │ │ │ ├── example.f90 │ │ │ ├── config.json │ │ │ └── tests.toml │ ├── collatz-conjecture │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── collatz_conjecture.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ └── collatz_conjecture_test.f90 │ ├── hello-world │ │ ├── .meta │ │ │ ├── example.f90 │ │ │ ├── tests.toml │ │ │ └── config.json │ │ ├── hello_world.f90 │ │ ├── hello_world_test.f90 │ │ └── .docs │ │ │ └── instructions.md │ ├── high-scores │ │ ├── high_scores.f90 │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ └── high_scores_test.f90 │ ├── pangram │ │ ├── pangram.f90 │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ └── pangram_test.f90 │ ├── bob │ │ ├── bob.f90 │ │ ├── .docs │ │ │ ├── introduction.md │ │ │ └── instructions.md │ │ └── .meta │ │ │ ├── config.json │ │ │ └── example.f90 │ ├── nth-prime │ │ ├── nth_prime.f90 │ │ ├── .docs │ │ │ └── instructions.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── tests.toml │ │ │ └── example.f90 │ │ └── nth_prime_test.f90 │ ├── reverse-string │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── reverse_string.f90 │ │ ├── .meta │ │ │ ├── example.f90 │ │ │ ├── config.json │ │ │ └── tests.toml │ │ └── reverse_string_test.f90 │ ├── perfect-numbers │ │ ├── perfect_numbers.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ └── .docs │ │ │ └── instructions.md │ ├── acronym │ │ ├── acronym.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── tests.toml │ │ │ └── example.f90 │ │ ├── .docs │ │ │ └── instructions.md │ │ └── acronym_test.f90 │ ├── rna-transcription │ │ ├── rna_transcription.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ ├── .docs │ │ │ ├── introduction.md │ │ │ └── instructions.md │ │ └── rna_transcription_test.f90 │ ├── armstrong-numbers │ │ ├── armstrong_numbers.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ ├── .docs │ │ │ └── instructions.md │ │ └── armstrong_numbers_test.f90 │ ├── binary-search │ │ ├── binary_search.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ ├── .docs │ │ │ ├── introduction.md │ │ │ └── instructions.md │ │ └── binary_search_test.f90 │ ├── hamming │ │ ├── hamming.f90 │ │ ├── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ └── hamming_test.f90 │ ├── queen-attack │ │ ├── .docs │ │ │ ├── instructions.append.md │ │ │ └── instructions.md │ │ ├── queen_attack.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ └── example.f90 │ │ └── queen_attack_test.f90 │ ├── darts │ │ ├── darts.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ ├── darts_test.f90 │ │ └── .docs │ │ │ └── instructions.md │ ├── sum-of-multiples │ │ ├── .docs │ │ │ ├── introduction.md │ │ │ └── instructions.md │ │ ├── sum_of_multiples.f90 │ │ └── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ ├── linked-list │ │ ├── .docs │ │ │ ├── introduction.md │ │ │ ├── hints.md │ │ │ └── instructions.md │ │ ├── .meta │ │ │ └── config.json │ │ └── linked_list.f90 │ ├── luhn │ │ ├── luhn.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ └── example.f90 │ │ └── .docs │ │ │ ├── introduction.md │ │ │ └── instructions.md │ ├── sieve │ │ ├── sieve.f90 │ │ ├── .docs │ │ │ └── introduction.md │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ └── sieve_test.f90 │ ├── roman-numerals │ │ ├── roman_numerals.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ └── example.f90 │ │ └── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ ├── space-age │ │ ├── space_age.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── tests.toml │ │ │ └── example.f90 │ │ ├── space_age_test.f90 │ │ └── .docs │ │ │ ├── instructions.md │ │ │ └── introduction.md │ ├── two-fer │ │ ├── two_fer.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ ├── .docs │ │ │ ├── introduction.md │ │ │ └── instructions.md │ │ └── two_fer_test.f90 │ ├── isbn-verifier │ │ ├── isbn_verifier.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ └── .docs │ │ │ └── instructions.md │ ├── isogram │ │ ├── isogram.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ └── .docs │ │ │ └── instructions.md │ ├── protein-translation │ │ ├── .meta │ │ │ ├── config.json │ │ │ └── example.f90 │ │ ├── protein_translation.f90 │ │ └── .docs │ │ │ └── instructions.md │ ├── rational-numbers │ │ ├── .meta │ │ │ ├── config.json │ │ │ └── example.f90 │ │ └── rational_numbers.f90 │ ├── difference-of-squares │ │ ├── difference_of_squares.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ ├── .docs │ │ │ └── instructions.md │ │ └── difference_of_squares_test.f90 │ ├── yacht │ │ ├── .meta │ │ │ └── config.json │ │ ├── .docs │ │ │ ├── introduction.md │ │ │ └── instructions.md │ │ └── yacht.f90 │ ├── allergies │ │ ├── allergies.f90 │ │ ├── .meta │ │ │ ├── config.json │ │ │ └── example.f90 │ │ └── .docs │ │ │ └── instructions.md │ ├── saddle-points │ │ ├── .meta │ │ │ ├── config.json │ │ │ ├── example.f90 │ │ │ └── tests.toml │ │ ├── saddle_points.f90 │ │ └── .docs │ │ │ ├── introduction.md │ │ │ └── instructions.md │ └── matrix │ │ ├── .meta │ │ ├── config.json │ │ ├── example.f90 │ │ └── tests.toml │ │ ├── .docs │ │ └── instructions.md │ │ ├── matrix.f90 │ │ └── matrix_test.f90 └── shared │ └── .docs │ └── help.md ├── bin ├── update-cmake-files ├── check-cmake-files-up-to-date └── add-exercise ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── configlet.yml │ ├── sync-labels.yml │ ├── cmake.yml │ ├── ping-cross-track-maintainers-team.yml │ ├── pause-community-contributions.yml │ ├── no-important-files-changed.yml │ └── ci.yml ├── .gitpod.Dockerfile ├── .gitpod.yml ├── .gitignore ├── .appends └── .github │ └── labels.yml ├── LICENSE ├── CMakeLists.txt └── config └── exercise_readme.go.tmpl /img/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/LEARNING.md: -------------------------------------------------------------------------------- 1 | # Learning 2 | 3 | - [Fortran quickstart](https://fortran-lang.org/learn/quickstart) 4 | -------------------------------------------------------------------------------- /testlib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.0) 2 | 3 | add_library(TesterMain STATIC TesterMain.f90 ) 4 | -------------------------------------------------------------------------------- /exercises/practice/leap/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine whether a given year is a leap year. 4 | -------------------------------------------------------------------------------- /bin/update-cmake-files: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for dir in exercises/*/*/; do 4 | cp config/CMakeLists.txt "$dir"/CMakeLists.txt 5 | done 6 | 7 | exit 0 8 | -------------------------------------------------------------------------------- /exercises/practice/triangle/.docs/hints.md: -------------------------------------------------------------------------------- 1 | The side lengths may be given as integers or as real values. 2 | Your program should be able to work with both types of input. 3 | -------------------------------------------------------------------------------- /exercises/practice/grains/.docs/hints.md: -------------------------------------------------------------------------------- 1 | The function for an individual square should take an integer value (`n`). 2 | Both functions should return a double precision value. 3 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Raindrops is a slightly more complex version of the FizzBuzz challenge, a classic interview question. 4 | -------------------------------------------------------------------------------- /docs/SNIPPET.txt: -------------------------------------------------------------------------------- 1 | module hello_world 2 | contains 3 | function hello() 4 | character(12) :: hello 5 | hello = 'Hello World' 6 | 7 | end function hello 8 | 9 | end module hello_world 10 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a positive integer, return the number of steps it takes to reach 1 according to the rules of the Collatz Conjecture. 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Code owners 2 | .github/CODEOWNERS @exercism/maintainers-admin 3 | 4 | # Changes to `fetch-configlet` should be made in the `exercism/configlet` repo 5 | bin/fetch-configlet @exercism/maintainers-admin 6 | 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | 5 | # Keep dependencies for GitHub Actions up-to-date 6 | - package-ecosystem: 'github-actions' 7 | directory: '/' 8 | schedule: 9 | interval: 'monthly' 10 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module hello_world 2 | contains 3 | function hello() 4 | character(13) :: hello 5 | hello = 'Hello, World!' 6 | 7 | end function hello 8 | 9 | end module hello_world 10 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/hello_world.f90: -------------------------------------------------------------------------------- 1 | module hello_world 2 | contains 3 | function hello() 4 | character(13) :: hello 5 | hello = 'Goodbye, Mars!' 6 | 7 | end function hello 8 | 9 | end module hello_world 10 | -------------------------------------------------------------------------------- /exercises/practice/high-scores/high_scores.f90: -------------------------------------------------------------------------------- 1 | 2 | module high_scores 3 | implicit none 4 | contains 5 | 6 | function scores(score_list) 7 | integer, dimension(:) :: score_list 8 | 9 | end function 10 | 11 | end module 12 | -------------------------------------------------------------------------------- /exercises/practice/pangram/pangram.f90: -------------------------------------------------------------------------------- 1 | module pangram 2 | implicit none 3 | contains 4 | 5 | logical function is_pangram(sentence) 6 | character(*) :: sentence 7 | 8 | end function is_pangram 9 | 10 | end module pangram 11 | -------------------------------------------------------------------------------- /exercises/practice/leap/leap.f90: -------------------------------------------------------------------------------- 1 | module leap 2 | implicit none 3 | 4 | contains 5 | 6 | logical function is_leap_year(year) 7 | integer :: year 8 | 9 | is_leap_year = .true. 10 | end function 11 | 12 | end module 13 | 14 | -------------------------------------------------------------------------------- /exercises/practice/bob/bob.f90: -------------------------------------------------------------------------------- 1 | module bob 2 | implicit none 3 | contains 4 | 5 | function hey(statement) 6 | character(100) :: hey 7 | character(len=*), intent(in) :: statement 8 | 9 | end function hey 10 | 11 | end module bob 12 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/collatz_conjecture.f90: -------------------------------------------------------------------------------- 1 | 2 | module collatz_conjecture 3 | implicit none 4 | contains 5 | 6 | integer function steps(i) 7 | integer :: i 8 | steps = -1 9 | end function 10 | 11 | end module 12 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/nth_prime.f90: -------------------------------------------------------------------------------- 1 | module nth_prime 2 | implicit none 3 | contains 4 | 5 | ! get nth prime 6 | integer function prime(n) 7 | integer, intent(in) :: n 8 | prime = -1 9 | end function 10 | 11 | end module 12 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/raindrops.f90: -------------------------------------------------------------------------------- 1 | module raindrops 2 | implicit none 3 | contains 4 | 5 | function convert(i) 6 | integer :: i 7 | character(20) :: convert 8 | 9 | end function convert 10 | 11 | end module raindrops 12 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full 2 | 3 | # Install custom tools, runtime, etc. 4 | RUN sudo apt-get update && sudo apt-get install -y gfortran && sudo apt-get clean && sudo rm -rf /var/cache/apt/* && sudo rm -rf /var/lib/apt/lists/* && sudo rm -rf /tmp/* 5 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to reverse a given string. 4 | 5 | Some examples: 6 | 7 | - Turn `"stressed"` into `"desserts"`. 8 | - Turn `"strops"` into `"sports"`. 9 | - Turn `"racecar"` into `"racecar"`. 10 | -------------------------------------------------------------------------------- /exercises/practice/perfect-numbers/perfect_numbers.f90: -------------------------------------------------------------------------------- 1 | 2 | module perfect_numbers 3 | implicit none 4 | 5 | contains 6 | 7 | character(len=9) function classify(num) 8 | integer, intent(in) :: num 9 | classify = "ERROR" 10 | end function 11 | 12 | end module 13 | -------------------------------------------------------------------------------- /exercises/practice/acronym/acronym.f90: -------------------------------------------------------------------------------- 1 | 2 | module acronym 3 | implicit none 4 | contains 5 | 6 | function abbreviate(s) 7 | character(len=*), intent(in) :: s 8 | character(len=len_trim(s)) :: abbreviate 9 | abbreviate=s(1:1) 10 | end function 11 | 12 | end module 13 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/rna_transcription.f90: -------------------------------------------------------------------------------- 1 | module rna_transcription 2 | implicit none 3 | contains 4 | 5 | function to_rna(dna) 6 | character(*) :: dna 7 | character(len(dna)) :: to_rna 8 | 9 | end function to_rna 10 | 11 | end module rna_transcription 12 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/armstrong_numbers.f90: -------------------------------------------------------------------------------- 1 | 2 | module armstrong_numbers 3 | implicit none 4 | contains 5 | 6 | logical function isArmstrongNumber(i) 7 | integer, intent(in) :: i 8 | 9 | isArmstrongNumber = .false. 10 | 11 | end function 12 | 13 | end module 14 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/hello_world_test.f90: -------------------------------------------------------------------------------- 1 | program hello_world_test_main 2 | use TesterMain 3 | use hello_world 4 | 5 | implicit none 6 | 7 | ! Test 1: Say Hi! 8 | call assert_equal("Hello, World!", hello(), "Say Hi!") 9 | 10 | call test_report() 11 | end program 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/configlet.yml: -------------------------------------------------------------------------------- 1 | name: Configlet 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | workflow_dispatch: 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | configlet: 15 | uses: exercism/github-actions/.github/workflows/configlet.yml@main 16 | -------------------------------------------------------------------------------- /exercises/practice/binary-search/binary_search.f90: -------------------------------------------------------------------------------- 1 | module binary_search 2 | implicit none 3 | contains 4 | 5 | function find(array, val) result(idx) 6 | integer, dimension(:), intent(in) :: array 7 | integer, intent(in) :: val 8 | integer :: idx 9 | 10 | end function 11 | 12 | end module 13 | -------------------------------------------------------------------------------- /exercises/practice/hamming/hamming.f90: -------------------------------------------------------------------------------- 1 | module hamming 2 | implicit none 3 | contains 4 | 5 | function compute(strand1, strand2, distance) 6 | character(*) :: strand1, strand2 7 | integer :: distance 8 | logical :: compute 9 | 10 | end function compute 11 | 12 | end module hamming 13 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/.docs/instructions.append.md: -------------------------------------------------------------------------------- 1 | ## Track-specific instructions 2 | 3 | In the Fortran version of this exercise, a queen's position is represented using an array of **one**-indexed coordinates. The white queen in the example above is at position `[4, 3]` and the black queen is at `[7, 6]`. 4 | -------------------------------------------------------------------------------- /bin/check-cmake-files-up-to-date: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | changed_files=$(diff -q --from-file=config/CMakeLists.txt exercises/*/*/CMakeLists.txt) 4 | 5 | if [ -n "$changed_files" ]; then 6 | echo "$changed_files" 7 | echo "run bin/update-cmake-files to update the cmake file of all exercises" 8 | exit 1 9 | fi 10 | -------------------------------------------------------------------------------- /exercises/practice/darts/darts.f90: -------------------------------------------------------------------------------- 1 | module darts 2 | implicit none 3 | 4 | contains 5 | 6 | function score(x, y) result(points) 7 | real, intent(in):: x, y 8 | integer :: points 9 | 10 | points = int(x + y) ! Replace this line with your implementation 11 | end function score 12 | 13 | end module darts 14 | -------------------------------------------------------------------------------- /exercises/practice/grains/grains.f90: -------------------------------------------------------------------------------- 1 | 2 | module grains 3 | 4 | implicit none 5 | 6 | contains 7 | 8 | double precision function square(n) 9 | integer :: n 10 | square = -1.d0 11 | end function 12 | 13 | double precision function total() 14 | total = -1.d0 15 | end function 16 | 17 | end module 18 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [af9ffe10-dc13-42d8-a742-e7bdafac449d] 6 | description = "Say Hi!" 7 | -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You work for a company that makes an online, fantasy-survival game. 4 | 5 | When a player finishes a level, they are awarded energy points. 6 | The amount of energy awarded depends on which magical items the player found while exploring that level. 7 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/reverse_string.f90: -------------------------------------------------------------------------------- 1 | module reverse_string 2 | implicit none 3 | contains 4 | 5 | function reverse(input) result(reversed) 6 | character(*), intent(in) :: input 7 | character(len=len(input)) :: reversed 8 | 9 | reversed = "Implement this function" 10 | end function 11 | 12 | end module 13 | -------------------------------------------------------------------------------- /exercises/practice/linked-list/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You are working on a project to develop a train scheduling system for a busy railway network. 4 | 5 | You've been asked to develop a prototype for the train routes in the scheduling system. 6 | Each route consists of a sequence of train stations that a given train stops at. 7 | -------------------------------------------------------------------------------- /exercises/practice/luhn/luhn.f90: -------------------------------------------------------------------------------- 1 | module luhn 2 | implicit none 3 | 4 | contains 5 | 6 | function validate(number) result(valid) 7 | character(*), intent(in) :: number 8 | logical :: valid 9 | 10 | valid = number == "123" ! Replace this line with your implementation 11 | end function validate 12 | 13 | end module luhn 14 | -------------------------------------------------------------------------------- /exercises/practice/sieve/sieve.f90: -------------------------------------------------------------------------------- 1 | module sieve 2 | implicit none 3 | 4 | contains 5 | 6 | function primes(limit) result(array) 7 | integer, intent(in) :: limit 8 | integer, allocatable :: array(:) 9 | 10 | array = [limit] ! Replace this line with your implementation 11 | end function primes 12 | 13 | end module sieve 14 | -------------------------------------------------------------------------------- /exercises/practice/roman-numerals/roman_numerals.f90: -------------------------------------------------------------------------------- 1 | module roman_numerals 2 | implicit none 3 | 4 | contains 5 | 6 | function roman(num) result(s) 7 | integer, value :: num 8 | character(15) :: s 9 | 10 | write(s, *) num ! Replace this line in your implementation 11 | end function roman 12 | 13 | end module roman_numerals 14 | -------------------------------------------------------------------------------- /exercises/practice/space-age/space_age.f90: -------------------------------------------------------------------------------- 1 | 2 | module space_age 3 | implicit none 4 | contains 5 | 6 | double precision function age_in_years(planet, seconds) 7 | character(len=*), intent(in) :: planet 8 | double precision, intent(in) :: seconds 9 | 10 | age_in_years = 0.d0 11 | 12 | end function 13 | 14 | end module 15 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/two_fer.f90: -------------------------------------------------------------------------------- 1 | module two_fer 2 | implicit none 3 | 4 | contains 5 | 6 | function twoFer(name) result(phrase) 7 | character(*), intent(in), optional :: name 8 | character(:), allocatable :: phrase 9 | 10 | phrase = name ! Replace this line with your implementation 11 | end function twoFer 12 | 13 | end module two_fer 14 | -------------------------------------------------------------------------------- /exercises/practice/isbn-verifier/isbn_verifier.f90: -------------------------------------------------------------------------------- 1 | module isbn_verifier 2 | implicit none 3 | 4 | contains 5 | 6 | function isValid(isbn) result(valid) 7 | character(*), intent(in) :: isbn 8 | logical :: valid 9 | 10 | valid = isbn == "123" ! Replace this line with your implementation 11 | end function isValid 12 | 13 | end module isbn_verifier 14 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a number n, determine what the nth prime is. 4 | 5 | By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. 6 | 7 | If your language provides methods in the standard library to deal with prime numbers, pretend they don't exist and implement them yourself. 8 | -------------------------------------------------------------------------------- /exercises/practice/isogram/isogram.f90: -------------------------------------------------------------------------------- 1 | module isogram 2 | implicit none 3 | 4 | contains 5 | 6 | function isIsogram(phrase) result(no_repeats) 7 | character(len=*), intent(in) :: phrase 8 | logical :: no_repeats 9 | 10 | no_repeats = phrase == "phrase" ! Replace this line with your implementation 11 | end function isIsogram 12 | 13 | end module isogram 14 | -------------------------------------------------------------------------------- /exercises/practice/bob/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Bob is a [lackadaisical][] teenager. 4 | He likes to think that he's very cool. 5 | And he definitely doesn't get excited about things. 6 | That wouldn't be cool. 7 | 8 | When people talk to him, his responses are pretty limited. 9 | 10 | [lackadaisical]: https://www.collinsdictionary.com/dictionary/english/lackadaisical 11 | -------------------------------------------------------------------------------- /exercises/practice/grains/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | There once was a wise servant who saved the life of a prince. 4 | The king promised to pay whatever the servant could dream up. 5 | Knowing that the king loved chess, the servant told the king he would like to have grains of wheat. 6 | One grain on the first square of a chessboard, with the number of grains doubling on each successive square. 7 | -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/sum_of_multiples.f90: -------------------------------------------------------------------------------- 1 | module sum_of_multiples 2 | implicit none 3 | 4 | contains 5 | 6 | function sum_multiples(factors, limit) result(res) 7 | integer, intent(in) :: factors(:), limit 8 | integer :: res 9 | 10 | res = sum(factors) - limit ! Replace this line with your implementation 11 | end function sum_multiples 12 | 13 | end module sum_of_multiples 14 | -------------------------------------------------------------------------------- /exercises/practice/grains/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Calculate the number of grains of wheat on a chessboard. 4 | 5 | A chessboard has 64 squares. 6 | Square 1 has one grain, square 2 has two grains, square 3 has four grains, and so on, doubling each time. 7 | 8 | Write code that calculates: 9 | 10 | - the number of grains on a given square 11 | - the total number of grains on the chessboard 12 | -------------------------------------------------------------------------------- /exercises/practice/high-scores/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Manage a game player's High Score list. 4 | 5 | Your task is to build a high-score component of the classic Frogger game, one of the highest selling and most addictive games of all time, and a classic of the arcade era. 6 | Your task is to write methods that return the highest score from the list, the last added score and the three highest scores. 7 | -------------------------------------------------------------------------------- /exercises/practice/linked-list/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "linked_list.f90" 8 | ], 9 | "test": [ 10 | "linked_list_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Implement a doubly linked list.", 17 | "source": "Classic computer science topic" 18 | } 19 | -------------------------------------------------------------------------------- /exercises/practice/protein-translation/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": ["D3usXMachina"], 3 | "files": { 4 | "solution": [ 5 | "protein_translation.f90" 6 | ], 7 | "test": [ 8 | "protein_translation_test.f90" 9 | ], 10 | "example": [ 11 | ".meta/example.f90" 12 | ] 13 | }, 14 | "blurb": "Translate RNA sequences into proteins.", 15 | "source": "Tyler Long" 16 | } 17 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/queen_attack.f90: -------------------------------------------------------------------------------- 1 | 2 | module queen_attack 3 | implicit none 4 | contains 5 | 6 | logical function isValid(pos) 7 | integer, dimension(2) :: pos 8 | isValid = .false. 9 | end function 10 | 11 | logical function canAttack(white_pos, black_pos) 12 | integer, dimension(2) :: white_pos, black_pos 13 | canAttack = .false. 14 | end function 15 | 16 | end module 17 | -------------------------------------------------------------------------------- /exercises/practice/pangram/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to figure out if a sentence is a pangram. 4 | 5 | A pangram is a sentence using every letter of the alphabet at least once. 6 | It is case insensitive, so it doesn't matter if a letter is lower-case (e.g. `k`) or upper-case (e.g. `K`). 7 | 8 | For this exercise, a sentence is a pangram if it contains each of the 26 letters in the English alphabet. 9 | -------------------------------------------------------------------------------- /exercises/practice/high-scores/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "high_scores.f90" 8 | ], 9 | "test": [ 10 | "high_scores_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Manage a player's High Score list.", 17 | "source": "Tribute to the eighties' arcade game Frogger" 18 | } 19 | -------------------------------------------------------------------------------- /exercises/practice/protein-translation/protein_translation.f90: -------------------------------------------------------------------------------- 1 | module protein_translation 2 | implicit none 3 | 4 | contains 5 | 6 | function proteins(rna) result(names) 7 | character(len=*), intent(in) :: rna 8 | character(len=13), allocatable :: names(:) 9 | 10 | names = [character(len=13) :: rna] ! Replace this line in your implementation 11 | end function proteins 12 | 13 | end module protein_translation 14 | 15 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Reversing strings (reading them from right to left, rather than from left to right) is a surprisingly common task in programming. 4 | 5 | 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. 6 | -------------------------------------------------------------------------------- /.github/workflows/sync-labels.yml: -------------------------------------------------------------------------------- 1 | name: Tools 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - .github/labels.yml 9 | - .github/workflows/sync-labels.yml 10 | workflow_dispatch: 11 | schedule: 12 | - cron: 0 0 1 * * # First day of each month 13 | 14 | permissions: 15 | issues: write 16 | 17 | jobs: 18 | sync-labels: 19 | uses: exercism/github-actions/.github/workflows/labels.yml@main 20 | -------------------------------------------------------------------------------- /exercises/practice/acronym/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "acronym.f90" 8 | ], 9 | "test": [ 10 | "acronym_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Convert a long phrase to its acronym.", 17 | "source": "Julien Vanier", 18 | "source_url": "https://github.com/monkbroc" 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: cmake 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | check-up-to-date: 11 | runs-on: ubuntu-24.04 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 15 | 16 | - name: Check if all exercise cmake files are up to date 17 | run: ./bin/check-cmake-files-up-to-date 18 | -------------------------------------------------------------------------------- /exercises/practice/isogram/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "isogram.f90" 8 | ], 9 | "test": [ 10 | "isogram_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Determine if a word or phrase is an isogram.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Isogram" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "two_fer.f90" 8 | ], 9 | "test": [ 10 | "two_fer_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Create a sentence of the form \"One for X, one for me.\".", 17 | "source_url": "https://github.com/exercism/problem-specifications/issues/757" 18 | } 19 | -------------------------------------------------------------------------------- /exercises/practice/darts/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "darts.f90" 8 | ], 9 | "test": [ 10 | "darts_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Calculate the points scored in a single toss of a Darts game.", 17 | "source": "Inspired by an exercise created by a professor Della Paolera in Argentina" 18 | } 19 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module reverse_string 2 | implicit none 3 | contains 4 | 5 | function reverse(input) result(reversed) 6 | character(*), intent(in) :: input 7 | character(len=len(input)) :: reversed 8 | integer :: length, i, idx 9 | 10 | length = len(input) 11 | 12 | do i = 1, length 13 | idx = length - i + 1 14 | reversed(i:i) = input(idx:idx) 15 | end do 16 | end function 17 | 18 | end module 19 | -------------------------------------------------------------------------------- /exercises/practice/isogram/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Determine if a word or phrase is an isogram. 4 | 5 | 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. 6 | 7 | Examples of isograms: 8 | 9 | - lumberjacks 10 | - background 11 | - downstream 12 | - six-year-old 13 | 14 | The word _isograms_, however, is not an isogram, because the s repeats. 15 | -------------------------------------------------------------------------------- /exercises/practice/rational-numbers/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "rational_numbers.f90" 8 | ], 9 | "test": [ 10 | "rational_numbers_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Implement rational numbers.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Rational_number" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/shared/.docs/help.md: -------------------------------------------------------------------------------- 1 | # Fortran resources 2 | 3 | ## Links 4 | 5 | - [Gnu Fortran (GFortran)](https://gcc.gnu.org/fortran/) 6 | - [GNU Fortran Documentation](https://gcc.gnu.org/onlinedocs/gfortran/) 7 | - [CMake Documentation](https://cmake.org/cmake/help/latest/) 8 | - [Intel Fortran](https://software.intel.com/en-us/fortran-compilers) 9 | - [Visual Studio](https://visualstudio.microsoft.com/) 10 | - [Fortran discourse channel](https://fortran-lang.discourse.group/) 11 | -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/difference_of_squares.f90: -------------------------------------------------------------------------------- 1 | module difference_of_squares 2 | implicit none 3 | contains 4 | 5 | integer function square_of_sum(n) 6 | integer :: n 7 | 8 | end function square_of_sum 9 | 10 | integer function sum_of_squares(n) 11 | integer :: n 12 | 13 | end function sum_of_squares 14 | 15 | integer function difference(n) 16 | integer :: n 17 | 18 | end function difference 19 | 20 | end module difference_of_squares 21 | -------------------------------------------------------------------------------- /exercises/practice/binary-search/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "SimaDovakin" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "binary_search.f90" 8 | ], 9 | "test": [ 10 | "binary_search_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Implement a binary search algorithm.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Binary_search_algorithm" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/yacht/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "yacht.f90" 8 | ], 9 | "test": [ 10 | "yacht_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Score a single throw of dice in the game Yacht.", 17 | "source": "James Kilfiger, using Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Yacht_(dice_game)" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/sieve/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You bought a big box of random computer parts at a garage sale. 4 | You've started putting the parts together to build custom computers. 5 | 6 | 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. 7 | You choose the famous "Sieve of Eratosthenes" algorithm, an ancient algorithm, but one that should push your computers to the limits. 8 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "nth_prime.f90" 8 | ], 9 | "test": [ 10 | "nth_prime_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Given a number n, determine what the nth prime is.", 17 | "source": "A variation on Problem 7 at Project Euler", 18 | "source_url": "https://projecteuler.net/problem=7" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "armstrong_numbers.f90" 8 | ], 9 | "test": [ 10 | "armstrong_numbers_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Determine if a number is an Armstrong number.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Narcissistic_number" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/leap/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module leap 2 | implicit none 3 | 4 | contains 5 | 6 | pure logical function is_leap_year(year) 7 | integer, intent(in) :: year 8 | 9 | is_leap_year = is_div(year, 4) & 10 | & .AND. .NOT. is_div(year, 100) & 11 | & .OR. is_div(year, 400) 12 | end function 13 | 14 | pure logical function is_div(a, b) 15 | integer, intent(in) :: a, b 16 | 17 | is_div = 0 == modulo(a, b) 18 | end function 19 | 20 | end module 21 | 22 | -------------------------------------------------------------------------------- /exercises/practice/roman-numerals/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "roman_numerals.f90" 8 | ], 9 | "test": [ 10 | "roman_numerals_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Convert modern Arabic numbers into Roman numerals.", 17 | "source": "The Roman Numeral Kata", 18 | "source_url": "https://codingdojo.org/kata/RomanNumerals/" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/luhn/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "luhn.f90" 8 | ], 9 | "test": [ 10 | "luhn_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Given a number determine whether or not it is valid per the Luhn formula.", 17 | "source": "The Luhn Algorithm on Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Luhn_algorithm" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | In some English accents, when you say "two for" quickly, it sounds like "two fer". 4 | Two-for-one is a way of saying that if you buy one, you also get one for free. 5 | So the phrase "two-fer" often implies a two-for-one offer. 6 | 7 | Imagine a bakery that has a holiday offer where you can buy two cookies for the price of one ("two-fer one!"). 8 | You take the offer and (very generously) decide to give the extra cookie to someone else in the queue. 9 | -------------------------------------------------------------------------------- /exercises/practice/leap/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "hiljusti" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "leap.f90" 8 | ], 9 | "test": [ 10 | "leap_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Determine whether a given year is a leap year.", 17 | "source": "CodeRanch Cattle Drive, Assignment 3", 18 | "source_url": "https://web.archive.org/web/20240907033714/https://coderanch.com/t/718816/Leap" 19 | } 20 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.Dockerfile 3 | 4 | # List the ports you want to expose and what to do when they are served. See https://www.gitpod.io/docs/config-ports/ 5 | ports: 6 | - port: 3000 7 | onOpen: open-preview 8 | 9 | # List the start up tasks. You can start them in parallel in multiple terminals. See https://www.gitpod.io/docs/config-start-tasks/ 10 | tasks: 11 | - command: echo 'Create build directory and run build and test' && mkdir build && cd build && cmake .. && make && ctest -V && cd .. 12 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "collatz_conjecture.f90" 8 | ], 9 | "test": [ 10 | "collatz_conjecture_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.", 17 | "source": "Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Collatz_conjecture" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/darts/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module darts 2 | implicit none 3 | 4 | contains 5 | 6 | function score(x, y) result(points) 7 | real, intent(in):: x, y 8 | integer :: points 9 | real :: dist 10 | 11 | dist = hypot(x, y) 12 | 13 | if (dist <= 1) then 14 | points = 10 15 | else if (dist <= 5) then 16 | points = 5 17 | else if (dist <= 10) then 18 | points = 1 19 | else 20 | points = 0 21 | end if 22 | end function score 23 | 24 | end module darts 25 | -------------------------------------------------------------------------------- /exercises/practice/sieve/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "sieve.f90" 8 | ], 9 | "test": [ 10 | "sieve_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Use the Sieve of Eratosthenes to find all the primes from 2 up to a given number.", 17 | "source": "Sieve of Eratosthenes at Wikipedia", 18 | "source_url": "https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes" 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/configlet 2 | bin/configlet.exe 3 | 4 | # We're using a very extensive ignore as there are many files we want to ignore, 5 | # included compiled binaries that have no extensions 6 | exercises/practice/*/** 7 | !exercises/practice/*/.docs/ 8 | !exercises/practice/*/.docs/* 9 | !exercises/practice/*/.meta/ 10 | !exercises/practice/*/.meta/* 11 | !exercises/practice/*/CMakeLists.txt 12 | !exercises/practice/*/**/*.f90 13 | exercises/practice/*/*_build_all.f90 14 | 15 | *.mod 16 | build/ 17 | __pycache__/ 18 | .vscode/ 19 | -------------------------------------------------------------------------------- /exercises/practice/allergies/allergies.f90: -------------------------------------------------------------------------------- 1 | 2 | module allergies 3 | implicit none 4 | 5 | contains 6 | 7 | logical function allergicTo(allergy_str, allergy_key) 8 | character(len=*), intent(in) :: allergy_str 9 | integer, intent(in) :: allergy_key 10 | allergicTo = .false. 11 | end function 12 | 13 | 14 | function allergicList(allergy_key) 15 | integer, intent(in) :: allergy_key 16 | character(len=100) :: allergicList 17 | allergicList = ' ' 18 | end function 19 | 20 | 21 | 22 | end module 23 | -------------------------------------------------------------------------------- /exercises/practice/saddle-points/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "saddle_points.f90" 8 | ], 9 | "test": [ 10 | "saddle_points_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Detect saddle points in a matrix.", 17 | "source": "J Dalbey's Programming Practice problems", 18 | "source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module collatz_conjecture 3 | implicit none 4 | contains 5 | 6 | integer function steps(i) 7 | integer :: i 8 | integer :: j 9 | if (i<1) then 10 | steps=-1 11 | return 12 | endif 13 | steps=0 14 | j = i 15 | do while (j>1) 16 | steps=steps+1 17 | if (mod(j,2)==0) then ! is even 18 | j=j/2 19 | else 20 | j=3*j+1 21 | endif 22 | end do 23 | 24 | end function 25 | 26 | end module 27 | 28 | -------------------------------------------------------------------------------- /.github/workflows/ping-cross-track-maintainers-team.yml: -------------------------------------------------------------------------------- 1 | name: Ping cross-track maintainers team 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | 8 | permissions: 9 | pull-requests: write 10 | 11 | jobs: 12 | ping: 13 | if: github.repository_owner == 'exercism' # Stops this job from running on forks 14 | uses: exercism/github-actions/.github/workflows/ping-cross-track-maintainers-team.yml@main 15 | secrets: 16 | github_membership_token: ${{ secrets.COMMUNITY_CONTRIBUTIONS_WORKFLOW_TOKEN }} 17 | -------------------------------------------------------------------------------- /exercises/practice/triangle/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "triangle.f90" 8 | ], 9 | "test": [ 10 | "triangle_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Determine if a triangle is equilateral, isosceles, or scalene.", 17 | "source": "The Ruby Koans triangle project, parts 1 & 2", 18 | "source_url": "https://web.archive.org/web/20220831105330/http://rubykoans.com" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/pangram/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "sentientmonkey" 4 | ], 5 | "contributors": [ 6 | "kotp", 7 | "pclausen", 8 | "sjwarner" 9 | ], 10 | "files": { 11 | "solution": [ 12 | "pangram.f90" 13 | ], 14 | "test": [ 15 | "pangram_test.f90" 16 | ], 17 | "example": [ 18 | ".meta/example.f90" 19 | ] 20 | }, 21 | "blurb": "Determine if a sentence is a pangram.", 22 | "source": "Wikipedia", 23 | "source_url": "https://en.wikipedia.org/wiki/Pangram" 24 | } 25 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "glennj" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "reverse_string.f90" 8 | ], 9 | "test": [ 10 | "reverse_string_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Reverse a given string.", 17 | "source": "Introductory challenge to reverse an input string", 18 | "source_url": "https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/saddle-points/saddle_points.f90: -------------------------------------------------------------------------------- 1 | module saddle_points 2 | implicit none 3 | 4 | type :: point_t 5 | integer :: row 6 | integer :: column 7 | end type point_t 8 | 9 | contains 10 | 11 | function saddlePoints(matrix) result(points) 12 | integer, intent(in) :: matrix(:, :) 13 | type(point_t), allocatable :: points(:) 14 | 15 | ! Replace the following line in your implementation 16 | points = [point_t(row = size(matrix), column = size(matrix))] 17 | end function saddlePoints 18 | 19 | end module saddle_points 20 | -------------------------------------------------------------------------------- /docs/RESOURCES.md: -------------------------------------------------------------------------------- 1 | # Fortran resources 2 | 3 | # Resources 4 | 5 | - [Fortran quickstart](https://fortran-lang.org/learn/quickstart) 6 | - [Fortran discourse channel](https://fortran-lang.discourse.group/) 7 | 8 | ## Links 9 | 10 | - [Gnu Fortran (GFortran)](https://gcc.gnu.org/fortran/) 11 | - [GNU Fortran Documentation](https://gcc.gnu.org/onlinedocs/gfortran/) 12 | - [CMake Documentation](https://cmake.org/cmake/help/latest/) 13 | - [Intel Fortran](https://software.intel.com/en-us/fortran-compilers) 14 | - [Visual Studio](https://visualstudio.microsoft.com/) 15 | -------------------------------------------------------------------------------- /exercises/practice/matrix/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "matrix.f90" 8 | ], 9 | "test": [ 10 | "matrix_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Given a string representing a matrix of numbers, return the rows and columns of that matrix.", 17 | "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", 18 | "source_url": "https://turing.edu" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/yacht/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Each year, something new is "all the rage" in your high school. 4 | This year it is a dice game: [Yacht][yacht]. 5 | 6 | The game of Yacht is from the same family as Poker Dice, Generala and particularly Yahtzee, of which it is a precursor. 7 | The game consists of twelve rounds. 8 | In each, five dice are rolled and the player chooses one of twelve categories. 9 | The chosen category is then used to score the throw of the dice. 10 | 11 | [yacht]: https://en.wikipedia.org/wiki/Yacht_(dice_game) 12 | -------------------------------------------------------------------------------- /exercises/practice/hamming/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Calculate the Hamming distance between two DNA strands. 4 | 5 | We read DNA using the letters C, A, G and T. 6 | Two strands might look like this: 7 | 8 | GAGCCTACTAACGGGAT 9 | CATCGTAATGACGGCCT 10 | ^ ^ ^ ^ ^ ^^ 11 | 12 | They have 7 differences, and therefore the Hamming distance is 7. 13 | 14 | ## Implementation notes 15 | 16 | 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. 17 | -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "sum_of_multiples.f90" 8 | ], 9 | "test": [ 10 | "sum_of_multiples_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Given a number, find the sum of all the multiples of particular numbers up to but not including that number.", 17 | "source": "A variation on Problem 1 at Project Euler", 18 | "source_url": "https://projecteuler.net/problem=1" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/grains/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module grains 3 | 4 | implicit none 5 | 6 | contains 7 | 8 | ! Using double precision return type instead of int to avoid overflow in int 9 | double precision function square(n) 10 | integer :: n 11 | square = -1.d0 12 | if (n>=1 .and. n<=64) then 13 | square = 2.d0**(n-1) 14 | end if 15 | end function 16 | 17 | double precision function total() 18 | integer :: i 19 | total=0.d0 20 | do i=1,64 21 | total = total +square(i) 22 | end do 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /exercises/practice/grains/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "grains.f90" 8 | ], 9 | "test": [ 10 | "grains_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Calculate the number of grains of wheat on a chessboard given that the number on each square doubles.", 17 | "source": "The CodeRanch Cattle Drive, Assignment 6", 18 | "source_url": "https://web.archive.org/web/20240908084142/https://coderanch.com/wiki/718824/Grains" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/space-age/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "space_age.f90" 8 | ], 9 | "test": [ 10 | "space_age_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Given an age in seconds, calculate how old someone is in terms of a given planet's solar years.", 17 | "source": "Partially inspired by Chapter 1 in Chris Pine's online Learn to Program tutorial.", 18 | "source_url": "https://pine.fm/LearnToProgram/?Chapter=01" 19 | } 20 | -------------------------------------------------------------------------------- /docs/ABOUT.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | Fortran is a general-purpose, compiled imperative programming language. 4 | Developed in the 1950s, it is the oldest high-level programming language. 5 | It is particularly useful for numeric computation and scientific computing. 6 | 7 | Fortran is portable and can run on almost any platform. 8 | As Fortran values stability and backwards compatibility, Fortran programs can run for decades. 9 | 10 | Fortran has been optimized for decades to execute efficiently, which has resulted in consistently being rated as one of the highest performing languages for energy and time. 11 | -------------------------------------------------------------------------------- /exercises/practice/allergies/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "allergies.f90" 8 | ], 9 | "test": [ 10 | "allergies_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies.", 17 | "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.", 18 | "source_url": "https://turing.edu" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/hamming/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "sentientmonkey" 4 | ], 5 | "contributors": [ 6 | "kotp", 7 | "pclausen", 8 | "sjwarner" 9 | ], 10 | "files": { 11 | "solution": [ 12 | "hamming.f90" 13 | ], 14 | "test": [ 15 | "hamming_test.f90" 16 | ], 17 | "example": [ 18 | ".meta/example.f90" 19 | ] 20 | }, 21 | "blurb": "Calculate the Hamming distance between two DNA strands.", 22 | "source": "The Calculating Point Mutations problem at Rosalind", 23 | "source_url": "https://rosalind.info/problems/hamm/" 24 | } 25 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module two_fer 2 | implicit none 3 | 4 | contains 5 | 6 | function twoFer(name) result(phrase) 7 | character(*), intent(in), optional :: name 8 | character(:), allocatable :: phrase 9 | character(:), allocatable :: newname 10 | 11 | if (present(name)) then 12 | allocate(character(len(name)) :: newname) 13 | newname = name 14 | else 15 | allocate(character(3) :: newname) 16 | newname = "you" 17 | end if 18 | 19 | phrase = "One for " // newname // ", one for me." 20 | end function twoFer 21 | 22 | end module two_fer 23 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module armstrong_numbers 3 | implicit none 4 | contains 5 | 6 | logical function isArmstrongNumber(i) 7 | integer, intent(in) :: i 8 | integer :: slen, idx, j, sum 9 | character(len=100) :: s 10 | 11 | isArmstrongNumber = .false. 12 | sum = 0 13 | write(s,'(i100)') i 14 | s=adjustl(s) 15 | slen = len_trim(s) 16 | do idx =1,slen 17 | read(s(idx:idx),*) j 18 | sum = sum + j**slen 19 | enddo 20 | if (sum == i) then 21 | isArmstrongNumber = .true. 22 | endif 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "queen_attack.f90" 8 | ], 9 | "test": [ 10 | "queen_attack_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other.", 17 | "source": "J Dalbey's Programming Practice problems", 18 | "source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/isbn-verifier/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "simisc" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "isbn_verifier.f90" 8 | ], 9 | "test": [ 10 | "isbn_verifier_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Check if a given string is a valid ISBN-10 number.", 17 | "source": "Converting a string into a number and some basic processing utilizing a relatable real world example.", 18 | "source_url": "https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "sentientmonkey" 4 | ], 5 | "contributors": [ 6 | "kotp", 7 | "pclausen" 8 | ], 9 | "files": { 10 | "solution": [ 11 | "hello_world.f90" 12 | ], 13 | "test": [ 14 | "hello_world_test.f90" 15 | ], 16 | "example": [ 17 | ".meta/example.f90" 18 | ] 19 | }, 20 | "blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".", 21 | "source": "This is an exercise to introduce users to using Exercism", 22 | "source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program" 23 | } 24 | -------------------------------------------------------------------------------- /exercises/practice/saddle-points/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You plan to build a tree house in the woods near your house so that you can watch the sun rise and set. 4 | 5 | You've obtained data from a local survey company that show the height of every tree in each rectangular section of the map. 6 | You need to analyze each grid on the map to find good trees for your tree house. 7 | 8 | A good tree is both: 9 | 10 | - taller than every tree to the east and west, so that you have the best possible view of the sunrises and sunsets. 11 | - shorter than every tree to the north and south, to minimize the amount of tree climbing. 12 | -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module sum_of_multiples 2 | implicit none 3 | 4 | contains 5 | 6 | function sum_multiples(factors, limit) result(res) 7 | integer, intent(in) :: factors(:), limit 8 | integer :: res 9 | integer :: i, j, factor, multiples(limit - 1) 10 | 11 | multiples = 0 12 | 13 | do i = 1, size(factors) 14 | factor = factors(i) 15 | if (factor == 0) cycle 16 | 17 | do j = factor, limit - 1, factor 18 | multiples(j) = j 19 | end do 20 | end do 21 | 22 | res = sum(multiples) 23 | end function sum_multiples 24 | 25 | end module sum_of_multiples 26 | -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "sentientmonkey" 4 | ], 5 | "contributors": [ 6 | "kotp", 7 | "pclausen" 8 | ], 9 | "files": { 10 | "solution": [ 11 | "difference_of_squares.f90" 12 | ], 13 | "test": [ 14 | "difference_of_squares_test.f90" 15 | ], 16 | "example": [ 17 | ".meta/example.f90" 18 | ] 19 | }, 20 | "blurb": "Find the difference between the square of the sum and the sum of the squares of the first N natural numbers.", 21 | "source": "Problem 6 at Project Euler", 22 | "source_url": "https://projecteuler.net/problem=6" 23 | } 24 | -------------------------------------------------------------------------------- /exercises/practice/perfect-numbers/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "pclausen" 4 | ], 5 | "files": { 6 | "solution": [ 7 | "perfect_numbers.f90" 8 | ], 9 | "test": [ 10 | "perfect_numbers_test.f90" 11 | ], 12 | "example": [ 13 | ".meta/example.f90" 14 | ] 15 | }, 16 | "blurb": "Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers.", 17 | "source": "Taken from Chapter 2 of Functional Thinking by Neal Ford.", 18 | "source_url": "https://www.oreilly.com/library/view/functional-thinking/9781449365509/" 19 | } 20 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [75c65189-8aef-471a-81de-0a90c728160c] 6 | description = "first prime" 7 | 8 | [2c38804c-295f-4701-b728-56dea34fd1a0] 9 | description = "second prime" 10 | 11 | [56692534-781e-4e8c-b1f9-3e82c1640259] 12 | description = "sixth prime" 13 | 14 | [fce1e979-0edb-412d-93aa-2c744e8f50ff] 15 | description = "big prime" 16 | 17 | [bd0a9eae-6df7-485b-a144-80e13c7d55b2] 18 | description = "there is no zeroth prime" 19 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "sentientmonkey" 4 | ], 5 | "contributors": [ 6 | "kotp", 7 | "pclausen", 8 | "sjwarner" 9 | ], 10 | "files": { 11 | "solution": [ 12 | "rna_transcription.f90" 13 | ], 14 | "test": [ 15 | "rna_transcription_test.f90" 16 | ], 17 | "example": [ 18 | ".meta/example.f90" 19 | ] 20 | }, 21 | "blurb": "Given a DNA strand, return its RNA complement.", 22 | "source": "Hyperphysics", 23 | "source_url": "https://web.archive.org/web/20220408112140/http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html" 24 | } 25 | -------------------------------------------------------------------------------- /exercises/practice/roman-numerals/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Your task is to convert a number from Arabic numerals to Roman numerals. 4 | 5 | For this exercise, we are only concerned about traditional Roman numerals, in which the largest number is MMMCMXCIX (or 3,999). 6 | 7 | ~~~~exercism/note 8 | There are lots of different ways to convert between Arabic and Roman numerals. 9 | We recommend taking a naive approach first to familiarise yourself with the concept of Roman numerals and then search for more efficient methods. 10 | 11 | Make sure to check out our Deep Dive video at the end to explore the different approaches you can take! 12 | ~~~~ 13 | -------------------------------------------------------------------------------- /exercises/practice/hamming/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module hamming 2 | 3 | implicit none 4 | contains 5 | 6 | function compute(strand1, strand2, distance) 7 | character(*) :: strand1, strand2 8 | integer :: distance, i 9 | logical :: compute 10 | 11 | distance = 0 12 | compute = .true. 13 | 14 | if ( len(strand1) .NE. len(strand2) ) then 15 | compute = .false. 16 | return 17 | end if 18 | 19 | do i = 1,len(strand1) 20 | if (strand1(i:i) .NE. strand2(i:i)) then 21 | distance = distance + 1 22 | end if 23 | 24 | end do 25 | 26 | end function compute 27 | end module hamming 28 | -------------------------------------------------------------------------------- /exercises/practice/bob/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "sentientmonkey" 4 | ], 5 | "contributors": [ 6 | "BNAndras", 7 | "kotp", 8 | "pclausen", 9 | "sjwarner" 10 | ], 11 | "files": { 12 | "solution": [ 13 | "bob.f90" 14 | ], 15 | "test": [ 16 | "bob_test.f90" 17 | ], 18 | "example": [ 19 | ".meta/example.f90" 20 | ] 21 | }, 22 | "blurb": "Bob is a lackadaisical teenager. In conversation, his responses are very limited.", 23 | "source": "Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial.", 24 | "source_url": "https://pine.fm/LearnToProgram/?Chapter=06" 25 | } 26 | -------------------------------------------------------------------------------- /exercises/practice/hello-world/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | The classical introductory exercise. 4 | Just say "Hello, World!". 5 | 6 | ["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment. 7 | 8 | The objectives are simple: 9 | 10 | - Modify the provided code so that it produces the string "Hello, World!". 11 | - Run the test suite and make sure that it succeeds. 12 | - Submit your solution and check it at the website. 13 | 14 | If everything goes well, you will be ready to fetch your first real exercise. 15 | 16 | [hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program 17 | -------------------------------------------------------------------------------- /exercises/practice/leap/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | A leap year (in the Gregorian calendar) occurs: 4 | 5 | - In every year that is evenly divisible by 4. 6 | - 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. 7 | 8 | Some examples: 9 | 10 | - 1997 was not a leap year as it's not divisible by 4. 11 | - 1900 was not a leap year as it's not divisible by 400. 12 | - 2000 was a leap year! 13 | 14 | ~~~~exercism/note 15 | 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). 16 | ~~~~ 17 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/nth_prime_test.f90: -------------------------------------------------------------------------------- 1 | program nth_prime_test_main 2 | use TesterMain 3 | use nth_prime 4 | 5 | implicit none 6 | 7 | ! Test 1: first prime 8 | call assert_equal(2, prime(1), "first prime") 9 | 10 | ! Test 2: second prime 11 | call assert_equal(3, prime(2), "second prime") 12 | 13 | ! Test 3: sixth prime 14 | call assert_equal(13, prime(6), "sixth prime") 15 | 16 | ! Test 4: big prime 17 | call assert_equal(104743, prime(10001), "big prime") 18 | 19 | ! Test 5: there is no zeroth prime 20 | call assert_equal(-1, prime(0), "there is no zeroth prime") 21 | 22 | call test_report() 23 | 24 | end program 25 | 26 | -------------------------------------------------------------------------------- /exercises/practice/acronym/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Convert a phrase to its acronym. 4 | 5 | Techies love their TLA (Three Letter Acronyms)! 6 | 7 | Help generate some jargon by writing a program that converts a long name like Portable Network Graphics to its acronym (PNG). 8 | 9 | Punctuation is handled as follows: hyphens are word separators (like whitespace); all other punctuation can be removed from the input. 10 | 11 | For example: 12 | 13 | | Input | Output | 14 | | ------------------------- | ------ | 15 | | As Soon As Possible | ASAP | 16 | | Liquid-crystal display | LCD | 17 | | Thank George It's Friday! | TGIF | 18 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/two_fer_test.f90: -------------------------------------------------------------------------------- 1 | ! The tests were created from https://github.com/exercism/problem-specifications/blob/main/exercises/two-fer/canonical-data.json 2 | 3 | program two_fer_test_main 4 | use TesterMain 5 | use two_fer 6 | implicit none 7 | 8 | ! Test 1: no name given 9 | call assert_equal("One for you, one for me.", twoFer(), "no name given") 10 | 11 | ! Test 2: a name given 12 | call assert_equal("One for Alice, one for me.", twoFer("Alice"), "a name given") 13 | 14 | ! Test 3: another name given 15 | call assert_equal("One for Bob, one for me.", twoFer("Bob"), "another name given") 16 | 17 | call test_report() 18 | 19 | end program 20 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module raindrops 2 | implicit none 3 | contains 4 | function convert(i) 5 | implicit none 6 | integer :: i 7 | character(20) :: convert 8 | 9 | convert = '' 10 | 11 | if ( mod(i,3) .eq. 0 ) then 12 | convert = 'Pling' 13 | end if 14 | if ( mod(i,5) .eq. 0 ) then 15 | convert = trim(convert)//'Plang' 16 | end if 17 | if ( mod(i,7) .eq. 0 ) then 18 | convert = trim(convert)//'Plong' 19 | end if 20 | 21 | if (convert .eq. '') then 22 | write( convert, '(i20)' ) i 23 | convert = trim(adjustl(convert)) 24 | end if 25 | 26 | end function convert 27 | end module raindrops 28 | -------------------------------------------------------------------------------- /exercises/practice/sieve/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module sieve 2 | implicit none 3 | 4 | contains 5 | 6 | function primes(limit) result(array) 7 | integer, intent(in) :: limit 8 | integer, allocatable :: array(:) 9 | logical :: composites(limit) 10 | integer :: temp(limit), n_primes, i, j 11 | 12 | composites = .false. 13 | n_primes = 0 14 | 15 | do i = 2, limit 16 | if (composites(i)) cycle 17 | 18 | n_primes = n_primes + 1 19 | temp(n_primes) = i 20 | 21 | do j = i ** 2, limit, i 22 | composites(j) = .true. 23 | end do 24 | end do 25 | 26 | array = temp(1:n_primes) 27 | end function primes 28 | 29 | end module sieve 30 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | 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. 4 | 5 | For example: 6 | 7 | - 9 is an Armstrong number, because `9 = 9^1 = 9` 8 | - 10 is _not_ an Armstrong number, because `10 != 1^2 + 0^2 = 1` 9 | - 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153` 10 | - 154 is _not_ an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` 11 | 12 | Write some code to determine whether a number is an Armstrong number. 13 | 14 | [armstrong-number]: https://en.wikipedia.org/wiki/Narcissistic_number 15 | -------------------------------------------------------------------------------- /exercises/practice/pangram/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You work for a company that sells fonts through their website. 4 | They'd like to show a different sentence each time someone views a font on their website. 5 | To give a comprehensive sense of the font, the random sentences should use **all** the letters in the English alphabet. 6 | 7 | They're running a competition to get suggestions for sentences that they can use. 8 | You're in charge of checking the submissions to see if they are valid. 9 | 10 | ~~~~exercism/note 11 | Pangram comes from Greek, παν γράμμα, pan gramma, which means "every letter". 12 | 13 | The best known English pangram is: 14 | 15 | > The quick brown fox jumps over the lazy dog. 16 | ~~~~ 17 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module queen_attack 3 | implicit none 4 | contains 5 | 6 | logical function isValid(pos) 7 | integer, dimension(2) :: pos 8 | ! check if valid 9 | isValid = all(pos(:) > 0) .and. all(pos(:) < 9) 10 | end function 11 | 12 | logical function canAttack(white_pos, black_pos) 13 | integer, dimension(2) :: white_pos, black_pos, dx 14 | canAttack = .false. 15 | if (isValid(white_pos) .and. isValid(black_pos)) then 16 | dx = abs(white_pos(:) - black_pos(:)) 17 | canAttack = dx(1)==0 & ! same row 18 | & .or. dx(2)==0 & ! same column 19 | & .or. dx(1)==dx(2) ! on diagonal 20 | endif 21 | end function 22 | 23 | end module 24 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine what you will say as you give away the extra cookie. 4 | 5 | If you know the person's name (e.g. if they're named Do-yun), then you will say: 6 | 7 | ```text 8 | One for Do-yun, one for me. 9 | ``` 10 | 11 | If you don't know the person's name, you will say _you_ instead. 12 | 13 | ```text 14 | One for you, one for me. 15 | ``` 16 | 17 | Here are some examples: 18 | 19 | | Name | Dialogue | 20 | | :----- | :-------------------------- | 21 | | Alice | One for Alice, one for me. | 22 | | Bohdan | One for Bohdan, one for me. | 23 | | | One for you, one for me. | 24 | | Zaphod | One for Zaphod, one for me. | 25 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | You work for a bioengineering company that specializes in developing therapeutic solutions. 4 | 5 | Your team has just been given a new project to develop a targeted therapy for a rare type of cancer. 6 | 7 | ~~~~exercism/note 8 | It's all very complicated, but the basic idea is that sometimes people's bodies produce too much of a given protein. 9 | That can cause all sorts of havoc. 10 | 11 | But if you can create a very specific molecule (called a micro-RNA), it can prevent the protein from being produced. 12 | 13 | This technique is called [RNA Interference][rnai]. 14 | 15 | [rnai]: https://admin.acceleratingscience.com/ask-a-scientist/what-is-rnai/ 16 | ~~~~ 17 | -------------------------------------------------------------------------------- /.github/workflows/pause-community-contributions.yml: -------------------------------------------------------------------------------- 1 | name: Pause Community Contributions 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | pull_request_target: 8 | types: 9 | - opened 10 | paths-ignore: 11 | - 'exercises/*/*/.approaches/**' 12 | - 'exercises/*/*/.articles/**' 13 | 14 | permissions: 15 | issues: write 16 | pull-requests: write 17 | 18 | jobs: 19 | pause: 20 | if: github.repository_owner == 'exercism' # Stops this job from running on forks 21 | uses: exercism/github-actions/.github/workflows/community-contributions.yml@main 22 | with: 23 | forum_category: fortran 24 | secrets: 25 | github_membership_token: ${{ secrets.COMMUNITY_CONTRIBUTIONS_WORKFLOW_TOKEN }} 26 | -------------------------------------------------------------------------------- /exercises/practice/linked-list/.docs/hints.md: -------------------------------------------------------------------------------- 1 | Implement the `list_t` type and the following procedures: 2 | 3 | - `new` returns an empty list. 4 | - `push` inserts an element with the specified value at the back of the list. 5 | - `pop` removes an element from the back of the list and returns the value of that element. 6 | - `unshift` inserts an element with the specified value at the front of the list. 7 | - `shift` removes an element from the front of the list and returns the value of that element. 8 | - `length` returns the number of elements in the list. 9 | - `delete` removes the first element with the specified value from the list. 10 | - `destroy` empties a list. 11 | 12 | Remember to release dynamically allocated memory when it is no longer needed. 13 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module rna_transcription 2 | implicit none 3 | contains 4 | function to_rna(dna) 5 | character(*) :: dna 6 | character(len(dna)) :: to_rna 7 | integer :: i 8 | 9 | do i = 1,len(dna) 10 | select case (dna(i:i)) 11 | case ('G') 12 | to_rna(i:i) = 'C' 13 | case ('C') 14 | to_rna(i:i) = 'G' 15 | case ('T') 16 | to_rna(i:i) = 'A' 17 | case ('A') 18 | to_rna(i:i) = 'U' 19 | case default 20 | to_rna = '' 21 | return 22 | end select 23 | end do 24 | 25 | end function to_rna 26 | end module rna_transcription 27 | 28 | -------------------------------------------------------------------------------- /.github/workflows/no-important-files-changed.yml: -------------------------------------------------------------------------------- 1 | name: No important files changed 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened] 6 | branches: [main] 7 | paths: 8 | - "exercises/concept/**" 9 | - "exercises/practice/**" 10 | - "!exercises/*/*/.approaches/**" 11 | - "!exercises/*/*/.articles/**" 12 | - "!exercises/*/*/.docs/**" 13 | - "!exercises/*/*/.meta/**" 14 | 15 | permissions: 16 | pull-requests: write 17 | 18 | jobs: 19 | check: 20 | uses: exercism/github-actions/.github/workflows/check-no-important-files-changed.yml@main 21 | with: 22 | repository: ${{ github.event.pull_request.head.repo.owner.login }}/${{ github.event.pull_request.head.repo.name }} 23 | ref: ${{ github.head_ref }} 24 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/.meta/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "sentientmonkey" 4 | ], 5 | "contributors": [ 6 | "kotp", 7 | "pclausen" 8 | ], 9 | "files": { 10 | "solution": [ 11 | "raindrops.f90" 12 | ], 13 | "test": [ 14 | "raindrops_test.f90" 15 | ], 16 | "example": [ 17 | ".meta/example.f90" 18 | ] 19 | }, 20 | "blurb": "Convert a number into its corresponding raindrop sounds - Pling, Plang and Plong.", 21 | "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.", 22 | "source_url": "https://en.wikipedia.org/wiki/Fizz_buzz" 23 | } 24 | -------------------------------------------------------------------------------- /exercises/practice/hamming/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Your body is made up of cells that contain DNA. 4 | Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. 5 | In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime! 6 | 7 | When cells divide, their DNA replicates too. 8 | Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. 9 | If we compare two strands of DNA and count the differences between them, we can see how many mistakes occurred. 10 | This is known as the "Hamming distance". 11 | 12 | The Hamming distance is useful in many areas of science, not just biology, so it's a nice phrase to be familiar with :) 13 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine the RNA complement of a given DNA sequence. 4 | 5 | Both DNA and RNA strands are a sequence of nucleotides. 6 | 7 | The four nucleotides found in DNA are adenine (**A**), cytosine (**C**), guanine (**G**), and thymine (**T**). 8 | 9 | The four nucleotides found in RNA are adenine (**A**), cytosine (**C**), guanine (**G**), and uracil (**U**). 10 | 11 | Given a DNA strand, its transcribed RNA strand is formed by replacing each nucleotide with its complement: 12 | 13 | - `G` -> `C` 14 | - `C` -> `G` 15 | - `T` -> `A` 16 | - `A` -> `U` 17 | 18 | ~~~~exercism/note 19 | If you want to look at how the inputs and outputs are structured, take a look at the examples in the test suite. 20 | ~~~~ 21 | -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Find the difference between the square of the sum and the sum of the squares of the first N natural numbers. 4 | 5 | The square of the sum of the first ten natural numbers is 6 | (1 + 2 + ... + 10)² = 55² = 3025. 7 | 8 | The sum of the squares of the first ten natural numbers is 9 | 1² + 2² + ... + 10² = 385. 10 | 11 | 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. 12 | 13 | You are not expected to discover an efficient solution to this yourself from first principles; research is allowed, indeed, encouraged. 14 | Finding the best algorithm for the problem is a key skill in software engineering. 15 | -------------------------------------------------------------------------------- /exercises/practice/luhn/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | At the Global Verification Authority, you've just been entrusted with a critical assignment. 4 | 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. 5 | The Luhn algorithm is a simple checksum formula used to help identify mistyped numbers. 6 | 7 | A batch of identifiers has just arrived on your desk. 8 | All of them must pass the Luhn test to ensure they're legitimate. 9 | If any fail, they'll be flagged as invalid, preventing mistakes such as incorrect transactions or failed account verifications. 10 | 11 | Can you ensure this is done right? The integrity of many services depends on you. 12 | -------------------------------------------------------------------------------- /exercises/practice/two-fer/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [1cf3e15a-a3d7-4a87-aeb3-ba1b43bc8dce] 13 | description = "no name given" 14 | 15 | [b4c6dbb8-b4fb-42c2-bafd-10785abe7709] 16 | description = "a name given" 17 | 18 | [3549048d-1a6e-4653-9a79-b0bda163e8d5] 19 | description = "another name given" 20 | -------------------------------------------------------------------------------- /exercises/practice/matrix/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a string representing a matrix of numbers, return the rows and columns of that matrix. 4 | 5 | So given a string with embedded newlines like: 6 | 7 | ```text 8 | 9 8 7 9 | 5 3 2 10 | 6 6 7 11 | ``` 12 | 13 | representing this matrix: 14 | 15 | ```text 16 | 1 2 3 17 | |--------- 18 | 1 | 9 8 7 19 | 2 | 5 3 2 20 | 3 | 6 6 7 21 | ``` 22 | 23 | your code should be able to spit out: 24 | 25 | - A list of the rows, reading each row left-to-right while moving top-to-bottom across the rows, 26 | - A list of the columns, reading each column top-to-bottom while moving from left-to-right. 27 | 28 | The rows for our example matrix: 29 | 30 | - 9, 8, 7 31 | - 5, 3, 2 32 | - 6, 6, 7 33 | 34 | And its columns: 35 | 36 | - 9, 5, 6 37 | - 8, 3, 6 38 | - 7, 2, 7 39 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [b4631f82-c98c-4a2f-90b3-c5c2b6c6f661] 6 | description = "Empty RNA sequence" 7 | 8 | [a9558a3c-318c-4240-9256-5d5ed47005a6] 9 | description = "RNA complement of cytosine is guanine" 10 | 11 | [6eedbb5c-12cb-4c8b-9f51-f8320b4dc2e7] 12 | description = "RNA complement of guanine is cytosine" 13 | 14 | [870bd3ec-8487-471d-8d9a-a25046488d3e] 15 | description = "RNA complement of thymine is adenine" 16 | 17 | [aade8964-02e1-4073-872f-42d3ffd74c5f] 18 | description = "RNA complement of adenine is uracil" 19 | 20 | [79ed2757-f018-4f47-a1d7-34a559392dbf] 21 | description = "RNA complement" 22 | -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module difference_of_squares 2 | contains 3 | integer function square_of_sum(n) 4 | implicit none 5 | integer :: i,n 6 | 7 | square_of_sum = 0 8 | 9 | do i = 1,n 10 | square_of_sum = square_of_sum + i 11 | end do 12 | 13 | square_of_sum = square_of_sum * square_of_sum 14 | end function square_of_sum 15 | 16 | integer function sum_of_squares(n) 17 | implicit none 18 | integer :: i, n 19 | 20 | sum_of_squares = 0 21 | 22 | do i = 1,n 23 | sum_of_squares = sum_of_squares + i**2 24 | end do 25 | 26 | end function sum_of_squares 27 | 28 | integer function difference(n) 29 | implicit none 30 | integer :: n 31 | 32 | difference = square_of_sum(n) - sum_of_squares(n) 33 | end function difference 34 | 35 | end module difference_of_squares 36 | -------------------------------------------------------------------------------- /exercises/practice/binary-search/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module binary_search 2 | implicit none 3 | contains 4 | 5 | function find(array, val) result(idx) 6 | integer, dimension(:), intent(in) :: array 7 | integer, intent(in) :: val 8 | integer :: idx 9 | integer :: start_index, end_index, middle_index 10 | 11 | start_index = 1 12 | end_index = size(array) 13 | 14 | do while (end_index >= start_index) 15 | middle_index = (end_index + start_index) / 2 16 | 17 | if (array(middle_index) == val) then 18 | idx = middle_index 19 | return 20 | end if 21 | 22 | if (array(middle_index) > val) then 23 | end_index = middle_index - 1 24 | else if (array(middle_index) < val) then 25 | start_index = middle_index + 1 26 | end if 27 | end do 28 | 29 | idx = -1 30 | end function 31 | 32 | end module 33 | -------------------------------------------------------------------------------- /exercises/practice/bob/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to determine what Bob will reply to someone when they say something to him or ask him a question. 4 | 5 | Bob only ever answers one of five things: 6 | 7 | - **"Sure."** 8 | This is his response if you ask him a question, such as "How are you?" 9 | The convention used for questions is that it ends with a question mark. 10 | - **"Whoa, chill out!"** 11 | This is his answer if you YELL AT HIM. 12 | The convention used for yelling is ALL CAPITAL LETTERS. 13 | - **"Calm down, I know what I'm doing!"** 14 | This is what he says if you yell a question at him. 15 | - **"Fine. Be that way!"** 16 | This is how he responds to silence. 17 | The convention used for silence is nothing, or various combinations of whitespace characters. 18 | - **"Whatever."** 19 | This is what he answers to anything else. 20 | -------------------------------------------------------------------------------- /exercises/practice/nth-prime/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module nth_prime 2 | implicit none 3 | contains 4 | 5 | ! loop from 2 to n/2. If mod(i,n)==0 this is not prime 6 | logical pure function is_prime(n) 7 | 8 | integer, intent(in) :: n 9 | integer :: i 10 | 11 | is_prime=.true. 12 | do i=2,n/2 13 | if ( mod(n,i)==0 ) then 14 | is_prime = .false. 15 | return 16 | end if 17 | end do 18 | end function 19 | 20 | ! get nth prime 21 | integer pure function prime(n) 22 | integer, intent(in) :: n 23 | integer :: i,j 24 | prime = -1 25 | if (n<1) then 26 | return 27 | endif 28 | j=0 29 | i=1 30 | do while (j> $GITHUB_ENV 32 | 33 | - name: Verify all exercises 34 | run: | 35 | mkdir build 36 | cd build 37 | cmake .. 38 | cmake --build . 39 | ctest -V 40 | -------------------------------------------------------------------------------- /exercises/practice/saddle-points/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to find the potential trees where you could build your tree house. 4 | 5 | The data company provides the data as grids that show the heights of the trees. 6 | The rows of the grid represent the east-west direction, and the columns represent the north-south direction. 7 | 8 | An acceptable tree will be the largest in its row, while being the smallest in its column. 9 | 10 | A grid might not have any good trees at all. 11 | Or it might have one, or even several. 12 | 13 | Here is a grid that has exactly one candidate tree. 14 | 15 | ```text 16 | ↓ 17 | 1 2 3 4 18 | |----------- 19 | 1 | 9 8 7 8 20 | → 2 |[5] 3 2 4 21 | 3 | 6 6 7 1 22 | ``` 23 | 24 | - Row 2 has values 5, 3, 2, and 4. The largest value is 5. 25 | - Column 1 has values 9, 5, and 6. The smallest value is 5. 26 | 27 | So the point at `[2, 1]` (row: 2, column: 1) is a great spot for a tree house. 28 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/collatz_conjecture_test.f90: -------------------------------------------------------------------------------- 1 | program collatz_conjecture_test_main 2 | use TesterMain 3 | use collatz_conjecture 4 | 5 | implicit none 6 | 7 | ! Test 1: zero steps for one 8 | call assert_equal(0, steps(1), "zero steps for one") 9 | 10 | ! Test 2: divide if even 11 | call assert_equal(4, steps(16), "divide if even") 12 | 13 | ! Test 3: even and odd steps 14 | call assert_equal(9, steps(12), "even and odd steps") 15 | 16 | ! Test 4: large number of even and odd steps 17 | call assert_equal(152, steps(1000000), "large number of even and odd steps") 18 | 19 | ! Test 5: zero is an error 20 | ! ERROR: Only positive numbers are allowed 21 | call assert_equal(-1, steps(0), "zero is an error") 22 | 23 | ! Test 6: negative value is an error 24 | ! ERROR: Only positive numbers are allowed 25 | call assert_equal(-1, steps(-15), "negative value is an error") 26 | 27 | call test_report() 28 | 29 | end program 30 | 31 | -------------------------------------------------------------------------------- /exercises/practice/saddle-points/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module saddle_points 2 | implicit none 3 | 4 | type :: point_t 5 | integer :: row 6 | integer :: column 7 | end type point_t 8 | 9 | contains 10 | 11 | function saddlePoints(matrix) result(points) 12 | integer, intent(in) :: matrix(:, :) 13 | type(point_t), allocatable :: points(:) 14 | integer :: n_points, i, j, & 15 | rmax(size(matrix, 1)), & 16 | cmin(size(matrix, 2)) 17 | type(point_t) :: temp_points(size(matrix)) 18 | 19 | rmax = maxval(matrix, dim=2) 20 | cmin = minval(matrix, dim=1) 21 | n_points = 0 22 | 23 | do j = 1, size(cmin) 24 | do i = 1, size(rmax) 25 | if (cmin(j) == rmax(i)) then 26 | n_points = n_points + 1 27 | temp_points(n_points) = point_t(row = i, column = j) 28 | end if 29 | end do 30 | end do 31 | 32 | points = temp_points(1:n_points) 33 | end function saddlePoints 34 | 35 | end module saddle_points 36 | -------------------------------------------------------------------------------- /exercises/practice/isogram/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module isogram 2 | implicit none 3 | 4 | contains 5 | 6 | function isIsogram(phrase) result(no_repeats) 7 | character(len=*), intent(in) :: phrase 8 | logical :: no_repeats 9 | logical :: seen(26) 10 | integer :: i, letter 11 | 12 | seen = .false. 13 | 14 | do i = 1, len_trim(phrase) 15 | select case (phrase(i:i)) 16 | case ('a':'z') 17 | letter = ichar(phrase(i:i)) - ichar('a') + 1 18 | case ('A':'Z') 19 | letter = ichar(phrase(i:i)) - ichar('A') + 1 20 | case ('-') 21 | cycle 22 | case (' ') 23 | cycle 24 | case default 25 | no_repeats = .false. 26 | return 27 | end select 28 | 29 | if (seen(letter)) then 30 | no_repeats = .false. 31 | return 32 | end if 33 | 34 | seen(letter) = .true. 35 | end do 36 | 37 | no_repeats = .true. 38 | end function isIsogram 39 | 40 | end module isogram 41 | -------------------------------------------------------------------------------- /exercises/practice/sieve/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [88529125-c4ce-43cc-bb36-1eb4ddd7b44f] 13 | description = "no primes under two" 14 | 15 | [4afe9474-c705-4477-9923-840e1024cc2b] 16 | description = "find first prime" 17 | 18 | [974945d8-8cd9-4f00-9463-7d813c7f17b7] 19 | description = "find primes up to 10" 20 | 21 | [2e2417b7-3f3a-452a-8594-b9af08af6d82] 22 | description = "limit is prime" 23 | 24 | [92102a05-4c7c-47de-9ed0-b7d5fcd00f21] 25 | description = "find primes up to 1000" 26 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/reverse_string_test.f90: -------------------------------------------------------------------------------- 1 | ! The tests were created from https://github.com/exercism/problem-specifications/blob/main/exercises/reverse-string/canonical-data.json 2 | 3 | program reverse_string_test_main 4 | use TesterMain 5 | use reverse_string 6 | implicit none 7 | 8 | ! Test 1: an empty string 9 | call assert_equal("", reverse(""), "an empty string") 10 | 11 | ! Test 2: a word 12 | call assert_equal("tobor", reverse("robot"), "a word") 13 | 14 | ! Test 3: a capitalized word 15 | call assert_equal("nemaR", reverse("Ramen"), "a capitalized word") 16 | 17 | ! Test 4: a sentence with punctuation 18 | call assert_equal("!yrgnuh m'I", reverse("I'm hungry!"), "a sentence with punctuation") 19 | 20 | ! Test 5: a palindrome 21 | call assert_equal("racecar", reverse("racecar"), "a palindrome") 22 | 23 | ! Test 6: an even-sized word 24 | call assert_equal("reward", reverse("drawer"), "an even-sized word") 25 | 26 | call test_report() 27 | 28 | end program 29 | 30 | -------------------------------------------------------------------------------- /exercises/practice/acronym/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [1e22cceb-c5e4-4562-9afe-aef07ad1eaf4] 6 | description = "basic" 7 | 8 | [79ae3889-a5c0-4b01-baf0-232d31180c08] 9 | description = "lowercase words" 10 | 11 | [ec7000a7-3931-4a17-890e-33ca2073a548] 12 | description = "punctuation" 13 | 14 | [32dd261c-0c92-469a-9c5c-b192e94a63b0] 15 | description = "all caps word" 16 | 17 | [ae2ac9fa-a606-4d05-8244-3bcc4659c1d4] 18 | description = "punctuation without whitespace" 19 | 20 | [0e4b1e7c-1a6d-48fb-81a7-bf65eb9e69f9] 21 | description = "very long abbreviation" 22 | 23 | [6a078f49-c68d-4b7b-89af-33a1a98c28cc] 24 | description = "consecutive delimiters" 25 | 26 | [5118b4b1-4572-434c-8d57-5b762e57973e] 27 | description = "apostrophes" 28 | 29 | [adc12eab-ec2d-414f-b48c-66a4fc06cdef] 30 | description = "underscore emphasis" 31 | -------------------------------------------------------------------------------- /exercises/practice/rna-transcription/rna_transcription_test.f90: -------------------------------------------------------------------------------- 1 | program rna_transcription_test_main 2 | use TesterMain 3 | use rna_transcription 4 | 5 | implicit none 6 | 7 | ! Test 1: Empty RNA sequence 8 | call assert_equal("", to_rna(""), "Empty RNA sequence") 9 | 10 | ! Test 2: RNA complement of cytosine is guanine 11 | call assert_equal("G", to_rna("C"), "RNA complement of cytosine is guanine") 12 | 13 | ! Test 3: RNA complement of guanine is cytosine 14 | call assert_equal("C", to_rna("G"), "RNA complement of guanine is cytosine") 15 | 16 | ! Test 4: RNA complement of thymine is adenine 17 | call assert_equal("A", to_rna("T"), "RNA complement of thymine is adenine") 18 | 19 | ! Test 5: RNA complement of adenine is uracil 20 | call assert_equal("U", to_rna("A"), "RNA complement of adenine is uracil") 21 | 22 | ! Test 6: RNA complement 23 | call assert_equal("UGCACCAGAAUU", to_rna("ACGTGGTCTTAA"), "RNA complement") 24 | 25 | call test_report() 26 | 27 | end program 28 | 29 | -------------------------------------------------------------------------------- /exercises/practice/matrix/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module matrix 3 | implicit none 4 | 5 | contains 6 | 7 | function row(m, m_dim, i) result(r) 8 | character(len=*), dimension(:) :: m 9 | integer, intent(in) :: m_dim(2) 10 | integer, intent(in) :: i 11 | integer :: r(m_dim(2)) 12 | integer :: A(m_dim(1),m_dim(2)) 13 | call read_m(m,m_dim, A) 14 | r(:) = A(i,:) 15 | end function 16 | 17 | function column(m, m_dim, j) result(c) 18 | character(len=*), dimension(:) :: m 19 | integer, intent(in) :: m_dim(2) 20 | integer, intent(in) :: j 21 | integer :: c(m_dim(1)) 22 | integer :: A(m_dim(1),m_dim(2)) 23 | call read_m(m,m_dim, A) 24 | c(:) = A(:,j) 25 | end function 26 | 27 | subroutine read_m(m,m_dim, A) 28 | character(len=*), dimension(:) :: m 29 | integer, intent(in) :: m_dim(2) 30 | integer :: A(m_dim(1),m_dim(2)) 31 | integer :: i 32 | 33 | do i=1,m_dim(1) 34 | read(m(i),*) A(i,:) 35 | enddo 36 | 37 | end subroutine 38 | 39 | end module 40 | -------------------------------------------------------------------------------- /exercises/practice/triangle/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Determine if a triangle is equilateral, isosceles, or scalene. 4 | 5 | An _equilateral_ triangle has all three sides the same length. 6 | 7 | An _isosceles_ triangle has at least two sides the same length. 8 | (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.) 9 | 10 | A _scalene_ triangle has all sides of different lengths. 11 | 12 | ## Note 13 | 14 | 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. 15 | 16 | In equations: 17 | 18 | Let `a`, `b`, and `c` be sides of the triangle. 19 | Then all three of the following expressions must be true: 20 | 21 | ```text 22 | a + b ≥ c 23 | b + c ≥ a 24 | a + c ≥ b 25 | ``` 26 | 27 | See [Triangle Inequality][triangle-inequality] 28 | 29 | [triangle-inequality]: https://en.wikipedia.org/wiki/Triangle_inequality 30 | -------------------------------------------------------------------------------- /.appends/.github/labels.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------------------------------------------- # 2 | # These are the repository-specific labels that augment the Exercise-wide labels defined in # 3 | # https://github.com/exercism/org-wide-files/blob/main/global-files/.github/labels.yml. # 4 | # ----------------------------------------------------------------------------------------- # 5 | 6 | - name: "bug" 7 | description: "" 8 | color: "ee0701" 9 | 10 | - name: "dependencies" 11 | description: "Pull requests that update a dependency file" 12 | color: "0366d6" 13 | 14 | - name: "duplicate" 15 | description: "" 16 | color: "cccccc" 17 | 18 | - name: "enhancement" 19 | description: "" 20 | color: "84b6eb" 21 | 22 | - name: "help wanted" 23 | description: "" 24 | color: "128A0C" 25 | 26 | - name: "invalid" 27 | description: "" 28 | color: "e6e6e6" 29 | 30 | - name: "question" 31 | description: "" 32 | color: "cc317c" 33 | 34 | - name: "wontfix" 35 | description: "" 36 | color: "ffffff" 37 | -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [e46c542b-31fc-4506-bcae-6b62b3268537] 6 | description = "square of sum 1" 7 | 8 | [9b3f96cb-638d-41ee-99b7-b4f9c0622948] 9 | description = "square of sum 5" 10 | 11 | [54ba043f-3c35-4d43-86ff-3a41625d5e86] 12 | description = "square of sum 100" 13 | 14 | [01d84507-b03e-4238-9395-dd61d03074b5] 15 | description = "sum of squares 1" 16 | 17 | [c93900cd-8cc2-4ca4-917b-dd3027023499] 18 | description = "sum of squares 5" 19 | 20 | [94807386-73e4-4d9e-8dec-69eb135b19e4] 21 | description = "sum of squares 100" 22 | 23 | [44f72ae6-31a7-437f-858d-2c0837adabb6] 24 | description = "difference of squares 1" 25 | 26 | [005cb2bf-a0c8-46f3-ae25-924029f8b00b] 27 | description = "difference of squares 5" 28 | 29 | [b1bf19de-9a16-41c0-a62b-1f02ecc0b036] 30 | description = "difference of squares 100" 31 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to convert a number into its corresponding raindrop sounds. 4 | 5 | If a given number: 6 | 7 | - is divisible by 3, add "Pling" to the result. 8 | - is divisible by 5, add "Plang" to the result. 9 | - is divisible by 7, add "Plong" to the result. 10 | - **is not** divisible by 3, 5, or 7, the result should be the number as a string. 11 | 12 | ## Examples 13 | 14 | - 28 is divisible by 7, but not 3 or 5, so the result would be `"Plong"`. 15 | - 30 is divisible by 3 and 5, but not 7, so the result would be `"PlingPlang"`. 16 | - 34 is not divisible by 3, 5, or 7, so the result would be `"34"`. 17 | 18 | ~~~~exercism/note 19 | A common way to test if one number is evenly divisible by another is to compare the [remainder][remainder] or [modulus][modulo] to zero. 20 | Most languages provide operators or functions for one (or both) of these. 21 | 22 | [remainder]: https://exercism.org/docs/programming/operators/remainder 23 | [modulo]: https://en.wikipedia.org/wiki/Modulo_operation 24 | ~~~~ 25 | -------------------------------------------------------------------------------- /exercises/practice/matrix/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [ca733dab-9d85-4065-9ef6-a880a951dafd] 6 | description = "extract row from one number matrix" 7 | 8 | [5c93ec93-80e1-4268-9fc2-63bc7d23385c] 9 | description = "can extract row" 10 | 11 | [2f1aad89-ad0f-4bd2-9919-99a8bff0305a] 12 | description = "extract row where numbers have different widths" 13 | 14 | [68f7f6ba-57e2-4e87-82d0-ad09889b5204] 15 | description = "can extract row from non-square matrix with no corresponding column" 16 | 17 | [e8c74391-c93b-4aed-8bfe-f3c9beb89ebb] 18 | description = "extract column from one number matrix" 19 | 20 | [7136bdbd-b3dc-48c4-a10c-8230976d3727] 21 | description = "can extract column" 22 | 23 | [ad64f8d7-bba6-4182-8adf-0c14de3d0eca] 24 | description = "can extract column from non-square matrix with no corresponding row" 25 | 26 | [9eddfa5c-8474-440e-ae0a-f018c2a0dd89] 27 | description = "extract column where numbers have different widths" 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Exercism 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /exercises/practice/allergies/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies. 4 | 5 | An allergy test produces a single numeric score which contains the information about all the allergies the person has (that they were tested for). 6 | 7 | The list of items (and their value) that were tested are: 8 | 9 | - eggs (1) 10 | - peanuts (2) 11 | - shellfish (4) 12 | - strawberries (8) 13 | - tomatoes (16) 14 | - chocolate (32) 15 | - pollen (64) 16 | - cats (128) 17 | 18 | So if Tom is allergic to peanuts and chocolate, he gets a score of 34. 19 | 20 | Now, given just that score of 34, your program should be able to say: 21 | 22 | - Whether Tom is allergic to any one of those allergens listed above. 23 | - All the allergens Tom is allergic to. 24 | 25 | Note: a given score may include allergens **not** listed above (i.e. allergens that score 256, 512, 1024, etc.). 26 | Your program should ignore those components of the score. 27 | For example, if the allergy score is 257, your program should only report the eggs (1) allergy. 28 | -------------------------------------------------------------------------------- /exercises/practice/perfect-numbers/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module perfect_numbers 3 | implicit none 4 | 5 | contains 6 | 7 | 8 | 9 | character(len=9) function classify(num) 10 | integer, intent(in) :: num 11 | integer :: rest 12 | integer :: i 13 | integer :: aliquot_sum 14 | classify = "ERROR" 15 | ! reject negative numbers 16 | if (num<=0)then 17 | return 18 | endif 19 | if (num==1)then 20 | ! Edge case (no factors other than itself) is classified correctly 21 | classify = "deficient" 22 | return 23 | endif 24 | aliquot_sum = 1 25 | ! get_divisors 26 | do i=2,num/2 27 | rest = mod(num,i) 28 | if (rest==0)then 29 | ! is divisor 30 | !write(*,*) 'DIV', num, i 31 | aliquot_sum = aliquot_sum+i 32 | endif 33 | enddo 34 | !write(*,*) 'aliquot_sum', num, aliquot_sum 35 | 36 | if (aliquot_sum==num) then 37 | classify = "perfect" 38 | else if (aliquot_sum>num) then 39 | classify = "abundant" 40 | else if (aliquot_sum 1 .and. mod(checksum, 10) == 0 29 | end function validate 30 | 31 | subroutine update(digit, ndigits, checksum) 32 | integer, intent(in) :: digit 33 | integer, intent(inout) :: ndigits, checksum 34 | 35 | ndigits = ndigits + 1 36 | 37 | if (mod(ndigits, 2) == 0) then 38 | checksum = checksum + 2 * mod(digit, 5) + digit / 5 39 | else 40 | checksum = checksum + digit 41 | end if 42 | end subroutine update 43 | 44 | end module luhn 45 | -------------------------------------------------------------------------------- /exercises/practice/rational-numbers/rational_numbers.f90: -------------------------------------------------------------------------------- 1 | 2 | module rational_numbers 3 | implicit none 4 | contains 5 | 6 | function add(r1,r2) 7 | integer,dimension(2) :: add, r1,r2 8 | ! Your code here 9 | end function 10 | 11 | function sub(r1,r2) 12 | integer,dimension(2) :: sub, r1,r2 13 | ! Your code here 14 | end function 15 | 16 | function mul(r1,r2) 17 | integer,dimension(2) :: mul, r1,r2 18 | ! Your code here 19 | end function 20 | 21 | function div(r1,r2) 22 | integer,dimension(2) :: div, r1,r2 23 | ! Your code here 24 | end function 25 | 26 | function rational_abs(r1) 27 | integer,dimension(2) :: rational_abs, r1 28 | ! Your code here 29 | end function 30 | 31 | function rational_to_pow(r1, ex) 32 | integer,dimension(2) :: rational_to_pow, r1 33 | integer :: ex 34 | ! Your code here 35 | end function 36 | 37 | function real_to_rational_pow(ex,r1) 38 | integer,dimension(2) :: r1 39 | real :: real_to_rational_pow,ex 40 | ! Your code here 41 | end function 42 | 43 | function reduce(r1) 44 | integer,dimension(2) :: reduce, r1 45 | ! Your code here 46 | end function 47 | 48 | end module 49 | -------------------------------------------------------------------------------- /exercises/practice/high-scores/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module high_scores 3 | implicit none 4 | contains 5 | 6 | function scores(score_list) 7 | integer, dimension(:) :: score_list 8 | integer, dimension(:) :: scores(size(score_list)) 9 | scores(:) = score_list(:) 10 | end function 11 | 12 | integer function latest(score_list) 13 | integer, dimension(:) :: score_list 14 | integer :: slen 15 | slen = size(score_list) 16 | latest = score_list(slen) 17 | end function 18 | 19 | 20 | integer function personalBest(score_list) 21 | integer, dimension(:) :: score_list 22 | personalBest = maxval(score_list) 23 | end function 24 | 25 | 26 | function personalTopThree(score_list) 27 | integer, dimension(:) :: score_list 28 | logical, dimension(:) :: score_list_mask(size(score_list)) 29 | integer, dimension(3) :: personalTopThree 30 | integer :: i 31 | integer :: j 32 | personalTopThree=[0,0,0] 33 | score_list_mask(:) = .true. 34 | do i=1,min(3, size(score_list)) 35 | personalTopThree(i) = maxval(score_list, mask=score_list_mask) 36 | j = maxloc(score_list, dim=1, mask=score_list_mask) 37 | score_list_mask(j) = .false. 38 | end do 39 | end function 40 | 41 | 42 | 43 | end module 44 | -------------------------------------------------------------------------------- /exercises/practice/difference-of-squares/difference_of_squares_test.f90: -------------------------------------------------------------------------------- 1 | program difference_of_squares_test_main 2 | use TesterMain 3 | use difference_of_squares 4 | 5 | implicit none 6 | 7 | ! Test 1: square of sum 1 8 | call assert_equal(1, square_of_sum(1), "square of sum 1") 9 | 10 | ! Test 2: square of sum 5 11 | call assert_equal(225, square_of_sum(5), "square of sum 5") 12 | 13 | ! Test 3: square of sum 100 14 | call assert_equal(25502500, square_of_sum(100), "square of sum 100") 15 | 16 | ! Test 1: sum of squares 1 17 | call assert_equal(1, sum_of_squares(1), "sum of squares 1") 18 | 19 | ! Test 2: sum of squares 5 20 | call assert_equal(55, sum_of_squares(5), "sum of squares 5") 21 | 22 | ! Test 3: sum of squares 100 23 | call assert_equal(338350, sum_of_squares(100), "sum of squares 100") 24 | 25 | ! Test 1: difference of squares 1 26 | call assert_equal(0, difference(1), "difference of squares 1") 27 | 28 | ! Test 2: difference of squares 5 29 | call assert_equal(170, difference(5), "difference of squares 5") 30 | 31 | ! Test 3: difference of squares 100 32 | call assert_equal(25164150, difference(100), "difference of squares 100") 33 | 34 | call test_report() 35 | 36 | end program 37 | 38 | -------------------------------------------------------------------------------- /exercises/practice/grains/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [9fbde8de-36b2-49de-baf2-cd42d6f28405] 6 | description = "grains on square 1" 7 | 8 | [ee1f30c2-01d8-4298-b25d-c677331b5e6d] 9 | description = "grains on square 2" 10 | 11 | [10f45584-2fc3-4875-8ec6-666065d1163b] 12 | description = "grains on square 3" 13 | 14 | [a7cbe01b-36f4-4601-b053-c5f6ae055170] 15 | description = "grains on square 4" 16 | 17 | [c50acc89-8535-44e4-918f-b848ad2817d4] 18 | description = "grains on square 16" 19 | 20 | [acd81b46-c2ad-4951-b848-80d15ed5a04f] 21 | description = "grains on square 32" 22 | 23 | [c73b470a-5efb-4d53-9ac6-c5f6487f227b] 24 | description = "grains on square 64" 25 | 26 | [1d47d832-3e85-4974-9466-5bd35af484e3] 27 | description = "square 0 raises an exception" 28 | 29 | [61974483-eeb2-465e-be54-ca5dde366453] 30 | description = "negative square raises an exception" 31 | 32 | [a95e4374-f32c-45a7-a10d-ffec475c012f] 33 | description = "square greater than 64 raises an exception" 34 | 35 | [6eb07385-3659-4b45-a6be-9dc474222750] 36 | description = "returns the total number of grains on the board" 37 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other. 4 | 5 | In the game of chess, a queen can attack pieces which are on the same row, column, or diagonal. 6 | 7 | A chessboard can be represented by an 8 by 8 array. 8 | 9 | So if you are told the white queen is at `c5` (zero-indexed at column 2, row 3) and the black queen at `f2` (zero-indexed at column 5, row 6), then you know that the set-up is like so: 10 | 11 | ![A chess board with two queens. Arrows emanating from the queen at c5 indicate possible directions of capture along file, rank and diagonal.](https://assets.exercism.org/images/exercises/queen-attack/queen-capture.svg) 12 | 13 | You are also able to answer whether the queens can attack each other. 14 | In this case, that answer would be yes, they can, because both pieces share a diagonal. 15 | 16 | ## Credit 17 | 18 | The chessboard image was made by [habere-et-dispertire][habere-et-dispertire] using LaTeX and the [chessboard package][chessboard-package] by Ulrike Fischer. 19 | 20 | [habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire 21 | [chessboard-package]: https://github.com/u-fischer/chessboard 22 | -------------------------------------------------------------------------------- /exercises/practice/space-age/space_age_test.f90: -------------------------------------------------------------------------------- 1 | program space_age_test_main 2 | use TesterMain 3 | use space_age 4 | 5 | implicit none 6 | 7 | ! Test 0: age on Neptune 8 | call assert_equal(0.35016863257806585d0, age_in_years("Neptune", 1821023456.d0), "age on Neptune") 9 | 10 | ! Test 1: age on Uranus 11 | call assert_equal(0.45641439979244397d0, age_in_years("Uranus", 1210123456.d0), "age on Uranus") 12 | 13 | ! Test 2: age on Saturn 14 | call assert_equal(2.1521752248037473d0, age_in_years("Saturn", 2000000000.d0), "age on Saturn") 15 | 16 | ! Test 3: age on Jupiter 17 | call assert_equal(2.4091431771337701d0, age_in_years("Jupiter", 901876382.d0), "age on Jupiter") 18 | 19 | ! Test 4: age on Mars 20 | call assert_equal(35.884187517994398d0, age_in_years("Mars", 2129871239.d0), "age on Mars") 21 | 22 | ! Test 5: age on Venus 23 | call assert_equal(9.778426831369266d0, age_in_years("Venus", 189839836.d0), "age on Venus") 24 | 25 | ! Test 6: age on Mercury 26 | call assert_equal(280.87933423985845d0, age_in_years("Mercury", 2134835688.d0), "age on Mercury") 27 | 28 | ! Test 7: age on Earth 29 | call assert_equal(31.688087814028950d0, age_in_years("Earth", 1000000000.d0), "age on Earth") 30 | 31 | call test_report() 32 | 33 | end program 34 | 35 | -------------------------------------------------------------------------------- /exercises/practice/yacht/yacht.f90: -------------------------------------------------------------------------------- 1 | 2 | module yacht 3 | implicit none 4 | 5 | ! | Ones | 1 × number of ones | Any combination | 1 1 1 4 5 scores 3 | 6 | ! | Twos | 2 × number of twos | Any combination | 2 2 3 4 5 scores 4 | 7 | ! | Threes | 3 × number of threes | Any combination | 3 3 3 3 3 scores 15 | 8 | ! | Fours | 4 × number of fours | Any combination | 1 2 3 3 5 scores 0 | 9 | ! | Fives | 5 × number of fives| Any combination | 5 1 5 2 5 scores 15 | 10 | ! | Sixes | 6 × number of sixes | Any combination | 2 3 4 5 6 scores 6 | 11 | ! | Full House | Total of the dice | Three of one number and two of another | 3 3 3 5 5 scores 19 | 12 | ! | Four of a Kind | Total of the four dice | At least four dice showing the same face | 4 4 4 4 6 scores 16 | 13 | ! | Little Straight | 30 points | 1-2-3-4-5 | 1 2 3 4 5 scores 30 | 14 | ! | Big Straight | 30 points | 2-3-4-5-6 | 2 3 4 5 6 scores 30 | 15 | ! | Choice | Sum of the dice | Any combination | 2 3 3 4 6 scores 18 | 16 | ! | Yacht | 50 points | All five dice showing the same face | 4 4 4 4 4 scores 50 | 17 | 18 | 19 | contains 20 | 21 | integer function score(dice, yacht_type) 22 | integer, dimension(5), intent(in) :: dice 23 | character(len=*), intent(in) :: yacht_type 24 | score=0 25 | end function 26 | 27 | 28 | end module 29 | -------------------------------------------------------------------------------- /exercises/practice/space-age/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given an age in seconds, calculate how old someone would be on a planet in our Solar System. 4 | 5 | One Earth year equals 365.25 Earth days, or 31,557,600 seconds. 6 | If you were told someone was 1,000,000,000 seconds old, their age would be 31.69 Earth-years. 7 | 8 | For the other planets, you have to account for their orbital period in Earth Years: 9 | 10 | | Planet | Orbital period in Earth Years | 11 | | ------- | ----------------------------- | 12 | | Mercury | 0.2408467 | 13 | | Venus | 0.61519726 | 14 | | Earth | 1.0 | 15 | | Mars | 1.8808158 | 16 | | Jupiter | 11.862615 | 17 | | Saturn | 29.447498 | 18 | | Uranus | 84.016846 | 19 | | Neptune | 164.79132 | 20 | 21 | ~~~~exercism/note 22 | The actual length of one complete orbit of the Earth around the sun is closer to 365.256 days (1 sidereal year). 23 | The Gregorian calendar has, on average, 365.2425 days. 24 | While not entirely accurate, 365.25 is the value used in this exercise. 25 | See [Year on Wikipedia][year] for more ways to measure a year. 26 | 27 | [year]: https://en.wikipedia.org/wiki/Year#Summary 28 | ~~~~ 29 | -------------------------------------------------------------------------------- /exercises/practice/roman-numerals/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module roman_numerals 2 | implicit none 3 | 4 | type :: numeral_t 5 | character(2) :: letter 6 | integer :: val 7 | end type numeral_t 8 | 9 | type(numeral_t), dimension(13), parameter :: numerals = [ & 10 | numeral_t(letter = 'M', val = 1000), & 11 | numeral_t(letter = 'CM', val = 900), & 12 | numeral_t(letter = 'D', val = 500), & 13 | numeral_t(letter = 'CD', val = 400), & 14 | numeral_t(letter = 'C', val = 100), & 15 | numeral_t(letter = 'XC', val = 90), & 16 | numeral_t(letter = 'L', val = 50), & 17 | numeral_t(letter = 'XL', val = 40), & 18 | numeral_t(letter = 'X', val = 10), & 19 | numeral_t(letter = 'IX', val = 9), & 20 | numeral_t(letter = 'V', val = 5), & 21 | numeral_t(letter = 'IV', val = 4), & 22 | numeral_t(letter = 'I', val = 1)] 23 | 24 | contains 25 | 26 | function roman(num) result(s) 27 | integer, value :: num 28 | character(15) :: s 29 | integer :: i 30 | 31 | s = '' 32 | do i = 1, size(numerals) 33 | associate (letter => numerals(i)%letter, val => numerals(i)%val) 34 | do while (val <= num) 35 | s = trim(s) // letter 36 | num = num - val 37 | end do 38 | end associate 39 | end do 40 | end function roman 41 | 42 | end module roman_numerals 43 | -------------------------------------------------------------------------------- /exercises/practice/space-age/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [84f609af-5a91-4d68-90a3-9e32d8a5cd34] 13 | description = "age on Earth" 14 | 15 | [ca20c4e9-6054-458c-9312-79679ffab40b] 16 | description = "age on Mercury" 17 | 18 | [502c6529-fd1b-41d3-8fab-65e03082b024] 19 | description = "age on Venus" 20 | 21 | [9ceadf5e-a0d5-4388-9d40-2c459227ceb8] 22 | description = "age on Mars" 23 | 24 | [42927dc3-fe5e-4f76-a5b5-f737fc19bcde] 25 | description = "age on Jupiter" 26 | 27 | [8469b332-7837-4ada-b27c-00ee043ebcad] 28 | description = "age on Saturn" 29 | 30 | [999354c1-76f8-4bb5-a672-f317b6436743] 31 | description = "age on Uranus" 32 | 33 | [80096d30-a0d4-4449-903e-a381178355d8] 34 | description = "age on Neptune" 35 | 36 | [57b96e2a-1178-40b7-b34d-f3c9c34e4bf4] 37 | description = "invalid planet causes error" 38 | include = false 39 | -------------------------------------------------------------------------------- /exercises/practice/triangle/triangle.f90: -------------------------------------------------------------------------------- 1 | 2 | module triangle 3 | implicit none 4 | 5 | interface equilateral 6 | module procedure equilateral_real 7 | module procedure equilateral_int 8 | end interface 9 | 10 | interface scalene 11 | module procedure scalene_real 12 | module procedure scalene_int 13 | end interface 14 | 15 | interface isosceles 16 | module procedure isosceles_real 17 | module procedure isosceles_int 18 | end interface 19 | 20 | contains 21 | 22 | logical function equilateral_real(edges) 23 | real,dimension(3) :: edges 24 | equilateral_real = .false. 25 | end function 26 | 27 | logical function equilateral_int(edges) 28 | integer,dimension(3) :: edges 29 | equilateral_int = .false. 30 | end function 31 | 32 | logical function isosceles_real(edges) 33 | real,dimension(3) :: edges 34 | isosceles_real = .false. 35 | end function 36 | 37 | logical function isosceles_int(edges) 38 | integer,dimension(3) :: edges 39 | isosceles_int = .false. 40 | end function 41 | 42 | 43 | logical function scalene_real(edges) 44 | real,dimension(3) :: edges 45 | scalene_real = .false. 46 | end function 47 | 48 | logical function scalene_int(edges) 49 | integer,dimension(3) :: edges 50 | scalene_int = .false. 51 | end function 52 | 53 | end module 54 | -------------------------------------------------------------------------------- /exercises/practice/space-age/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | 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). 4 | The first stop is Mercury, where customs require you to fill out a form (bureaucracy is apparently _not_ Earth-specific). 5 | As you hand over the form to the customs officer, they scrutinize it and frown. 6 | "Do you _really_ expect me to believe you're just 50 years old? 7 | You must be closer to 200 years old!" 8 | 9 | Amused, you wait for the customs officer to start laughing, but they appear to be dead serious. 10 | You realize that you've entered your age in _Earth years_, but the officer expected it in _Mercury years_! 11 | As Mercury's orbital period around the sun is significantly shorter than Earth, you're actually a lot older in Mercury years. 12 | After some quick calculations, you're able to provide your age in Mercury Years. 13 | The customs officer smiles, satisfied, and waves you through. 14 | You make a mental note to pre-calculate your planet-specific age _before_ future customs checks, to avoid such mix-ups. 15 | 16 | ~~~~exercism/note 17 | If you're wondering why Pluto didn't make the cut, go watch [this YouTube video][pluto-video]. 18 | 19 | [pluto-video]: https://www.youtube.com/watch?v=Z_2gbGXzFbs 20 | ~~~~ 21 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.0) 2 | project(exercism Fortran) 3 | include(CTest) 4 | 5 | set(EXERCISM_RUN_ALL_TESTS 1) 6 | 7 | # Activate Fortran compiler warnings 8 | if(CMAKE_Fortran_COMPILER_ID MATCHES "Intel") # Intel fortran 9 | if(WIN32) 10 | set (CMAKE_Fortran_FLAGS "/warn:all") 11 | else() 12 | set (CMAKE_Fortran_FLAGS "-warn all") 13 | endif() 14 | endif() 15 | if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU") # GFortran 16 | set (CMAKE_Fortran_FLAGS "-std=f2008 -W -Wall -Wextra -pedantic -fbacktrace") 17 | endif() 18 | 19 | set(practicedir ${CMAKE_CURRENT_SOURCE_DIR}/exercises/practice) 20 | 21 | 22 | function(travis_fixup exercise) 23 | string(REPLACE "-" "_" file ${exercise}) 24 | set(subdir ${practicedir}/${exercise}) 25 | if(EXISTS ${subdir}/.meta/example.f90) 26 | configure_file( ${subdir}/.meta/example.f90 ${subdir}/${file}_build_all.f90) 27 | endif() 28 | endfunction() 29 | 30 | add_subdirectory(testlib) 31 | include_directories(testlib ${CMAKE_CURRENT_BINARY_DIR}/testlib) 32 | 33 | file(GLOB exercise_list ${practicedir}/*/CMakeLists.txt) 34 | 35 | foreach(exercise_cmake ${exercise_list}) 36 | get_filename_component(exercise_dir ${exercise_cmake} DIRECTORY) 37 | get_filename_component(exercise ${exercise_dir} NAME) 38 | travis_fixup(${exercise}) 39 | add_subdirectory(${exercise_dir}) 40 | endforeach() 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to write the code that calculates the energy points that get awarded to players when they complete a level. 4 | 5 | The points awarded depend on two things: 6 | 7 | - The level (a number) that the player completed. 8 | - The base value of each magical item collected by the player during that level. 9 | 10 | The energy points are awarded according to the following rules: 11 | 12 | 1. For each magical item, take the base value and find all the multiples of that value that are less than the level number. 13 | 2. Combine the sets of numbers. 14 | 3. Remove any duplicates. 15 | 4. Calculate the sum of all the numbers that are left. 16 | 17 | Let's look at an example: 18 | 19 | **The player completed level 20 and found two magical items with base values of 3 and 5.** 20 | 21 | 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. 22 | 23 | - Multiples of 3 less than 20: `{3, 6, 9, 12, 15, 18}` 24 | - Multiples of 5 less than 20: `{5, 10, 15}` 25 | - Combine the sets and remove duplicates: `{3, 5, 6, 9, 10, 12, 15, 18}` 26 | - Sum the unique multiples: `3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 = 78` 27 | - Therefore, the player earns **78** energy points for completing level 20 and finding the two magical items with base values of 3 and 5. 28 | -------------------------------------------------------------------------------- /exercises/practice/reverse-string/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [c3b7d806-dced-49ee-8543-933fd1719b1c] 13 | description = "an empty string" 14 | 15 | [01ebf55b-bebb-414e-9dec-06f7bb0bee3c] 16 | description = "a word" 17 | 18 | [0f7c07e4-efd1-4aaa-a07a-90b49ce0b746] 19 | description = "a capitalized word" 20 | 21 | [71854b9c-f200-4469-9f5c-1e8e5eff5614] 22 | description = "a sentence with punctuation" 23 | 24 | [1f8ed2f3-56f3-459b-8f3e-6d8d654a1f6c] 25 | description = "a palindrome" 26 | 27 | [b9e7dec1-c6df-40bd-9fa3-cd7ded010c4c] 28 | description = "an even-sized word" 29 | 30 | [1bed0f8a-13b0-4bd3-9d59-3d0593326fa2] 31 | description = "wide characters" 32 | include = false 33 | 34 | [93d7e1b8-f60f-4f3c-9559-4056e10d2ead] 35 | description = "grapheme cluster with pre-combined form" 36 | include = false 37 | 38 | [1028b2c1-6763-4459-8540-2da47ca512d9] 39 | description = "grapheme clusters" 40 | include = false 41 | -------------------------------------------------------------------------------- /exercises/practice/acronym/acronym_test.f90: -------------------------------------------------------------------------------- 1 | program acronym_test_main 2 | use TesterMain 3 | use acronym 4 | 5 | implicit none 6 | 7 | ! Test 1: basic 8 | call assert_equal("PNG", abbreviate("Portable Network Graphics"), "basic") 9 | 10 | ! Test 2: lowercase words 11 | call assert_equal("ROR", abbreviate("Ruby on Rails"), "lowercase words") 12 | 13 | ! Test 3: punctuation 14 | call assert_equal("FIFO", abbreviate("First In, First Out"), "punctuation") 15 | 16 | ! Test 4: all caps word 17 | call assert_equal("GIMP", abbreviate("GNU Image Manipulation Program"), "all caps word") 18 | 19 | ! Test 5: punctuation without whitespace 20 | call assert_equal("CMOS", abbreviate("Complementary metal-oxide semiconductor"), "punctuation without whitespace") 21 | 22 | ! Test 6: very long abbreviation 23 | call assert_equal("ROTFLSHTMDCOALM", abbreviate(& 24 | & "Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me"), "very long abbreviation") 25 | ! Test 7: consecutive delimiters 26 | call assert_equal("SIMUFTA", abbreviate("Something - I made up from thin air"), "consecutive delimiters") 27 | 28 | ! Test 8: apostrophes 29 | call assert_equal("HC", abbreviate("Halley's Comet"), "apostrophes") 30 | 31 | ! Test 9: underscore emphasis 32 | call assert_equal("TRNT", abbreviate("The Road _Not_ Taken"), "underscore emphasis") 33 | 34 | call test_report() 35 | 36 | end program 37 | 38 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [540a3d51-e7a6-47a5-92a3-4ad1838f0bfd] 13 | description = "zero steps for one" 14 | 15 | [3d76a0a6-ea84-444a-821a-f7857c2c1859] 16 | description = "divide if even" 17 | 18 | [754dea81-123c-429e-b8bc-db20b05a87b9] 19 | description = "even and odd steps" 20 | 21 | [ecfd0210-6f85-44f6-8280-f65534892ff6] 22 | description = "large number of even and odd steps" 23 | 24 | [7d4750e6-def9-4b86-aec7-9f7eb44f95a3] 25 | description = "zero is an error" 26 | include = false 27 | 28 | [2187673d-77d6-4543-975e-66df6c50e2da] 29 | description = "zero is an error" 30 | reimplements = "7d4750e6-def9-4b86-aec7-9f7eb44f95a3" 31 | 32 | [c6c795bf-a288-45e9-86a1-841359ad426d] 33 | description = "negative value is an error" 34 | include = false 35 | 36 | [ec11f479-56bc-47fd-a434-bcd7a31a7a2e] 37 | description = "negative value is an error" 38 | reimplements = "c6c795bf-a288-45e9-86a1-841359ad426d" 39 | -------------------------------------------------------------------------------- /exercises/practice/high-scores/high_scores_test.f90: -------------------------------------------------------------------------------- 1 | program high_scores_test_main 2 | use TesterMain 3 | use high_scores 4 | 5 | implicit none 6 | 7 | ! Test 1: List of scores 8 | call assert_equal([30, 50, 20, 70], scores([30, 50, 20, 70]), "List of scores") 9 | 10 | ! Test 2: Latest score 11 | call assert_equal(30, latest([100, 0, 90, 30]), "Latest score") 12 | 13 | ! Test 3: Personal best 14 | call assert_equal(100, personalBest([40, 100, 70]), "Personal best") 15 | 16 | ! Test 4: Personal top three from a list of scores 17 | call assert_equal([100, 90, 70], personalTopThree( & 18 | & [10, 30, 90, 30, 100, 20, 10, 0, 30, 40, 40, 70, 70]), & 19 | & "Personal top three from a list of scores") 20 | ! Test 5: Personal top highest to lowest 21 | call assert_equal([30, 20, 10], personalTopThree([20, 10, 30]), & 22 | & "Personal top highest to lowest") 23 | ! Test 6: Personal top when there is a tie 24 | call assert_equal([40, 40, 30], personalTopThree([40, 20, 40, 30]), & 25 | & "Personal top when there is a tie") 26 | ! Test 7: Personal top when there are less than 3 27 | call assert_equal([70, 30, 0], personalTopThree([30, 70]), & 28 | & "Personal top when there are less than 3") 29 | ! Test 8: Personal top when there is only one 30 | call assert_equal([40, 0, 0], personalTopThree([40]), & 31 | & "Personal top when there is only one") 32 | 33 | call test_report() 34 | 35 | end program 36 | 37 | -------------------------------------------------------------------------------- /exercises/practice/collatz-conjecture/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | One evening, you stumbled upon an old notebook filled with cryptic scribbles, as though someone had been obsessively chasing an idea. 4 | On one page, a single question stood out: **Can every number find its way to 1?** 5 | It was tied to something called the **Collatz Conjecture**, a puzzle that has baffled thinkers for decades. 6 | 7 | The rules were deceptively simple. 8 | Pick any positive integer. 9 | 10 | - If it's even, divide it by 2. 11 | - If it's odd, multiply it by 3 and add 1. 12 | 13 | Then, repeat these steps with the result, continuing indefinitely. 14 | 15 | Curious, you picked number 12 to test and began the journey: 16 | 17 | 12 ➜ 6 ➜ 3 ➜ 10 ➜ 5 ➜ 16 ➜ 8 ➜ 4 ➜ 2 ➜ 1 18 | 19 | Counting from the second number (6), it took 9 steps to reach 1, and each time the rules repeated, the number kept changing. 20 | At first, the sequence seemed unpredictable — jumping up, down, and all over. 21 | Yet, the conjecture claims that no matter the starting number, we'll always end at 1. 22 | 23 | It was fascinating, but also puzzling. 24 | Why does this always seem to work? 25 | Could there be a number where the process breaks down, looping forever or escaping into infinity? 26 | 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. 27 | 28 | [collatz-prize]: https://mathprize.net/posts/collatz-conjecture/ 29 | -------------------------------------------------------------------------------- /exercises/practice/linked-list/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your team has decided to use a doubly linked list to represent each train route in the schedule. 4 | Each station along the train's route will be represented by a node in the linked list. 5 | 6 | You don't need to worry about arrival and departure times at the stations. 7 | Each station will simply be represented by a number. 8 | 9 | Routes can be extended, adding stations to the beginning or end of a route. 10 | They can also be shortened by removing stations from the beginning or the end of a route. 11 | 12 | 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. 13 | 14 | The size of a route is measured not by how far the train travels, but by how many stations it stops at. 15 | 16 | ~~~~exercism/note 17 | The linked list is a fundamental data structure in computer science, often used in the implementation of other data structures. 18 | As the name suggests, it is a list of nodes that are linked together. 19 | It is a list of "nodes", where each node links to its neighbor or neighbors. 20 | In a **singly linked list** each node links only to the node that follows it. 21 | In a **doubly linked list** each node links to both the node that comes before, as well as the node that comes after. 22 | 23 | If you want to dig deeper into linked lists, check out [this article][intro-linked-list] that explains it using nice drawings. 24 | 25 | [intro-linked-list]: https://medium.com/basecs/whats-a-linked-list-anyway-part-1-d8b7e6508b9d 26 | ~~~~ 27 | -------------------------------------------------------------------------------- /exercises/practice/binary-search/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Your task is to implement a binary search algorithm. 4 | 5 | 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. 6 | 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. 7 | 8 | ~~~~exercism/caution 9 | Binary search only works when a list has been sorted. 10 | ~~~~ 11 | 12 | The algorithm looks like this: 13 | 14 | - Find the middle element of a _sorted_ list and compare it with the item we're looking for. 15 | - If the middle element is our item, then we're done! 16 | - If the middle element is greater than our item, we can eliminate that element and all the elements **after** it. 17 | - If the middle element is less than our item, we can eliminate that element and all the elements **before** it. 18 | - If every element of the list has been eliminated then the item is not in the list. 19 | - Otherwise, repeat the process on the part of the list that has not been eliminated. 20 | 21 | Here's an example: 22 | 23 | Let's say we're looking for the number 23 in the following sorted list: `[4, 8, 12, 16, 23, 28, 32]`. 24 | 25 | - We start by comparing 23 with the middle element, 16. 26 | - Since 23 is greater than 16, we can eliminate the left half of the list, leaving us with `[23, 28, 32]`. 27 | - We then compare 23 with the new middle element, 28. 28 | - Since 23 is less than 28, we can eliminate the right half of the list: `[23]`. 29 | - We've found our item. 30 | -------------------------------------------------------------------------------- /exercises/practice/acronym/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module acronym 3 | implicit none 4 | contains 5 | 6 | logical pure function is_lower_alfa(c) 7 | character, intent(in) :: c 8 | is_lower_alfa=.false. 9 | if ( c .ge. 'a' .and. c .le. 'z') then 10 | is_lower_alfa=.true. 11 | endif 12 | end function 13 | 14 | logical pure function is_upper_alfa(c) 15 | character, intent(in) :: c 16 | is_upper_alfa=.false. 17 | if ( c .ge. 'A' .and. c .le. 'Z') then 18 | is_upper_alfa=.true. 19 | endif 20 | end function 21 | 22 | logical pure function is_alfa(c) 23 | character, intent(in) :: c 24 | is_alfa = is_lower_alfa(c) .or. is_upper_alfa(c) 25 | end function 26 | 27 | character pure function to_upper(c) 28 | character, intent(in) :: c 29 | integer, parameter :: K=ichar('A') - ichar('a') 30 | to_upper=c 31 | if (.not. is_upper_alfa(c)) then 32 | to_upper=char(ichar(c)+K) 33 | endif 34 | end function 35 | 36 | 37 | function abbreviate(s) 38 | character(len=*), intent(in) :: s 39 | character(len=len_trim(s)) :: abbreviate 40 | integer :: i 41 | integer :: j 42 | integer :: k 43 | abbreviate=to_upper(s(1:1)) 44 | j=0 45 | k=0 46 | do i=1,len_trim(s) 47 | if (is_alfa(s(i:i))) then 48 | j=j+1 49 | if (j==1) then 50 | k=k+1 51 | abbreviate(k:k)=to_upper(s(i:i)) 52 | end if 53 | else if (s(i:i)=="'") then 54 | ! do nothing for appostrophe ' 55 | continue 56 | else 57 | j=0 58 | end if 59 | end do 60 | end function 61 | 62 | end module 63 | -------------------------------------------------------------------------------- /exercises/practice/leap/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | [6466b30d-519c-438e-935d-388224ab5223] 12 | description = "year not divisible by 4 in common year" 13 | 14 | [ac227e82-ee82-4a09-9eb6-4f84331ffdb0] 15 | description = "year divisible by 2, not divisible by 4 in common year" 16 | 17 | [4fe9b84c-8e65-489e-970b-856d60b8b78e] 18 | description = "year divisible by 4, not divisible by 100 in leap year" 19 | 20 | [7fc6aed7-e63c-48f5-ae05-5fe182f60a5d] 21 | description = "year divisible by 4 and 5 is still a leap year" 22 | 23 | [78a7848f-9667-4192-ae53-87b30c9a02dd] 24 | description = "year divisible by 100, not divisible by 400 in common year" 25 | 26 | [9d70f938-537c-40a6-ba19-f50739ce8bac] 27 | description = "year divisible by 100 but not by 3 is still not a leap year" 28 | 29 | [42ee56ad-d3e6-48f1-8e3f-c84078d916fc] 30 | description = "year divisible by 400 is leap year" 31 | 32 | [57902c77-6fe9-40de-8302-587b5c27121e] 33 | description = "year divisible by 400 but not by 125 is still a leap year" 34 | 35 | [c30331f6-f9f6-4881-ad38-8ca8c12520c1] 36 | description = "year divisible by 200, not divisible by 400 in common year" 37 | -------------------------------------------------------------------------------- /exercises/practice/pangram/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [64f61791-508e-4f5c-83ab-05de042b0149] 13 | description = "empty sentence" 14 | 15 | [74858f80-4a4d-478b-8a5e-c6477e4e4e84] 16 | description = "perfect lower case" 17 | 18 | [61288860-35ca-4abe-ba08-f5df76ecbdcd] 19 | description = "only lower case" 20 | 21 | [6564267d-8ac5-4d29-baf2-e7d2e304a743] 22 | description = "missing the letter 'x'" 23 | 24 | [c79af1be-d715-4cdb-a5f2-b2fa3e7e0de0] 25 | description = "missing the letter 'h'" 26 | 27 | [d835ec38-bc8f-48e4-9e36-eb232427b1df] 28 | description = "with underscores" 29 | 30 | [8cc1e080-a178-4494-b4b3-06982c9be2a8] 31 | description = "with numbers" 32 | 33 | [bed96b1c-ff95-45b8-9731-fdbdcb6ede9a] 34 | description = "missing letters replaced by numbers" 35 | 36 | [938bd5d8-ade5-40e2-a2d9-55a338a01030] 37 | description = "mixed case and punctuation" 38 | 39 | [2577bf54-83c8-402d-a64b-a2c0f7bb213a] 40 | description = "case insensitive" 41 | include = false 42 | 43 | [7138e389-83e4-4c6e-8413-1e40a0076951] 44 | description = "a-m and A-M are 26 different characters but not a pangram" 45 | reimplements = "2577bf54-83c8-402d-a64b-a2c0f7bb213a" 46 | include = false 47 | -------------------------------------------------------------------------------- /exercises/practice/saddle-points/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [3e374e63-a2e0-4530-a39a-d53c560382bd] 13 | description = "Can identify single saddle point" 14 | 15 | [6b501e2b-6c1f-491f-b1bb-7f278f760534] 16 | description = "Can identify that empty matrix has no saddle points" 17 | 18 | [8c27cc64-e573-4fcb-a099-f0ae863fb02f] 19 | description = "Can identify lack of saddle points when there are none" 20 | 21 | [6d1399bd-e105-40fd-a2c9-c6609507d7a3] 22 | description = "Can identify multiple saddle points in a column" 23 | 24 | [3e81dce9-53b3-44e6-bf26-e328885fd5d1] 25 | description = "Can identify multiple saddle points in a row" 26 | 27 | [88868621-b6f4-4837-bb8b-3fad8b25d46b] 28 | description = "Can identify saddle point in bottom right corner" 29 | 30 | [5b9499ca-fcea-4195-830a-9c4584a0ee79] 31 | description = "Can identify saddle points in a non square matrix" 32 | 33 | [ee99ccd2-a1f1-4283-ad39-f8c70f0cf594] 34 | description = "Can identify that saddle points in a single column matrix are those with the minimum value" 35 | 36 | [63abf709-a84b-407f-a1b3-456638689713] 37 | description = "Can identify that saddle points in a single row matrix are those with the maximum value" 38 | -------------------------------------------------------------------------------- /exercises/practice/grains/grains_test.f90: -------------------------------------------------------------------------------- 1 | program grains_test_main 2 | use TesterMain 3 | use grains 4 | 5 | implicit none 6 | 7 | ! Test 1: grains on square 1 8 | call assert_equal(1.d0, square(1), "grains on square 1") 9 | 10 | ! Test 2: grains on square 2 11 | call assert_equal(2.d0, square(2), "grains on square 2") 12 | 13 | ! Test 3: grains on square 3 14 | call assert_equal(4.d0, square(3), "grains on square 3") 15 | 16 | ! Test 4: grains on square 4 17 | call assert_equal(8.d0, square(4), "grains on square 4") 18 | 19 | ! Test 5: grains on square 16 20 | call assert_equal(32768.d0, square(16), "grains on square 16") 21 | 22 | ! Test 6: grains on square 32 23 | call assert_equal(2147483648.d0, square(32), "grains on square 32") 24 | 25 | ! Test 7: grains on square 64 26 | call assert_equal(9223372036854775808.d0, square(64), "grains on square 64") 27 | 28 | ! Test 8: square 0 raises an exception 29 | ! ERROR: square must be between 1 and 64 30 | call assert_equal(-1.d0, square(0), "square 0 raises an exception") 31 | 32 | ! Test 9: negative square raises an exception 33 | ! ERROR: square must be between 1 and 64 34 | call assert_equal(-1.d0, square(-1), "negative square raises an exception") 35 | 36 | ! Test 10: square greater than 64 raises an exception 37 | ! ERROR: square must be between 1 and 64 38 | call assert_equal(-1.d0, square(65), "square greater than 64 raises an exception") 39 | 40 | ! Test 11: returns the total number of grains on the board 41 | call assert_equal(18446744073709551615.d0, total(), "returns the total number of grains on the board") 42 | 43 | call test_report() 44 | 45 | end program 46 | 47 | -------------------------------------------------------------------------------- /exercises/practice/pangram/pangram_test.f90: -------------------------------------------------------------------------------- 1 | program pangram_test_main 2 | use TesterMain 3 | use pangram 4 | 5 | implicit none 6 | 7 | ! Test 1: empty sentence 8 | call assert_equal(.false., is_pangram(""), "empty sentence") 9 | 10 | ! Test 2: perfect lower case 11 | call assert_equal(.true., is_pangram("abcdefghijklmnopqrstuvwxyz"), "perfect lower case") 12 | 13 | ! Test 3: only lower case 14 | call assert_equal(.true., is_pangram("the quick brown fox jumps over the lazy dog"), "only lower case") 15 | 16 | ! Test 4: missing the letter 'x' 17 | call assert_equal(.false., is_pangram("a quick movement of the enemy will jeopardize five gunboats"), "missing the letter 'x'") 18 | 19 | ! Test 5: missing the letter 'h' 20 | call assert_equal(.false., is_pangram("five boxing wizards jump quickly at it"), "missing the letter 'h'") 21 | 22 | ! Test 6: with underscores 23 | call assert_equal(.true., is_pangram("the_quick_brown_fox_jumps_over_the_lazy_dog"), "with underscores") 24 | 25 | ! Test 7: with numbers 26 | call assert_equal(.true., is_pangram("the 1 quick brown fox jumps over the 2 lazy dogs"), "with numbers") 27 | 28 | ! Test 8: missing letters replaced by numbers 29 | call assert_equal(.false., is_pangram("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog"), "missing letters replaced by numbers") 30 | 31 | ! Test 9: mixed case and punctuation 32 | call assert_equal(.true., is_pangram("Five quacking Zephyrs jolt my wax bed."), "mixed case and punctuation") 33 | 34 | ! Test 10: case insensitive 35 | call assert_equal(.false., is_pangram("the quick brown fox jumps over with lazy FX"), "case insensitive") 36 | 37 | call test_report() 38 | 39 | end program 40 | 41 | -------------------------------------------------------------------------------- /exercises/practice/perfect-numbers/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers. 4 | 5 | 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]. 6 | The _aliquot sum_ is defined as the sum of the factors of a number not including the number itself. 7 | For example, the aliquot sum of `15` is `1 + 3 + 5 = 9`. 8 | 9 | ## Perfect 10 | 11 | A number is perfect when it equals its aliquot sum. 12 | For example: 13 | 14 | - `6` is a perfect number because `1 + 2 + 3 = 6` 15 | - `28` is a perfect number because `1 + 2 + 4 + 7 + 14 = 28` 16 | 17 | ## Abundant 18 | 19 | A number is abundant when it is less than its aliquot sum. 20 | For example: 21 | 22 | - `12` is an abundant number because `1 + 2 + 3 + 4 + 6 = 16` 23 | - `24` is an abundant number because `1 + 2 + 3 + 4 + 6 + 8 + 12 = 36` 24 | 25 | ## Deficient 26 | 27 | A number is deficient when it is greater than its aliquot sum. 28 | For example: 29 | 30 | - `8` is a deficient number because `1 + 2 + 4 = 7` 31 | - Prime numbers are deficient 32 | 33 | ## Task 34 | 35 | Implement a way to determine whether a given number is [perfect](#perfect). 36 | 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). 37 | 38 | [nicomachus]: https://en.wikipedia.org/wiki/Nicomachus 39 | [aliquot-sum]: https://en.wikipedia.org/wiki/Aliquot_sum 40 | -------------------------------------------------------------------------------- /exercises/practice/sieve/sieve_test.f90: -------------------------------------------------------------------------------- 1 | ! The tests were created from https://github.com/exercism/problem-specifications/blob/main/exercises/sieve/canonical-data.json 2 | 3 | program sieve_test_main 4 | use TesterMain 5 | use sieve 6 | implicit none 7 | 8 | ! Test 1: no primes under two 9 | call assert_equal([integer::], primes(1), "no primes under two") 10 | 11 | ! Test 2: find first prime 12 | call assert_equal([2], primes(2), "find first prime") 13 | 14 | ! Test 3: find primes up to 10 15 | call assert_equal([2, 3, 5, 7], primes(10), "find primes up to 10") 16 | 17 | ! Test 4: limit is prime 18 | call assert_equal([2, 3, 5, 7, 11, 13], primes(13), "limit is prime") 19 | 20 | ! Test 5: find primes up to 1000 21 | call assert_equal([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, & 22 | 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, & 23 | 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, & 24 | 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, & 25 | 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, & 26 | 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, & 27 | 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, & 28 | 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, & 29 | 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, & 30 | 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, & 31 | 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, & 32 | 997], primes(1000), "find primes up to 1000") 33 | 34 | call test_report() 35 | 36 | end program 37 | -------------------------------------------------------------------------------- /exercises/practice/isbn-verifier/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | The [ISBN-10 verification process][isbn-verification] is used to validate book identification numbers. 4 | These normally contain dashes and look like: `3-598-21508-8` 5 | 6 | ## ISBN 7 | 8 | The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). 9 | In the case the check character is an X, this represents the value '10'. 10 | These may be communicated with or without hyphens, and can be checked for their validity by the following formula: 11 | 12 | ```text 13 | (d₁ * 10 + d₂ * 9 + d₃ * 8 + d₄ * 7 + d₅ * 6 + d₆ * 5 + d₇ * 4 + d₈ * 3 + d₉ * 2 + d₁₀ * 1) mod 11 == 0 14 | ``` 15 | 16 | If the result is 0, then it is a valid ISBN-10, otherwise it is invalid. 17 | 18 | ## Example 19 | 20 | Let's take the ISBN-10 `3-598-21508-8`. 21 | We plug it in to the formula, and get: 22 | 23 | ```text 24 | (3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0 25 | ``` 26 | 27 | Since the result is 0, this proves that our ISBN is valid. 28 | 29 | ## Task 30 | 31 | Given a string the program should check if the provided string is a valid ISBN-10. 32 | Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN. 33 | 34 | The program should be able to verify ISBN-10 both with and without separating dashes. 35 | 36 | ## Caveats 37 | 38 | Converting from strings to numbers can be tricky in certain languages. 39 | Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). 40 | For instance `3-598-21507-X` is a valid ISBN-10. 41 | 42 | [isbn-verification]: https://en.wikipedia.org/wiki/International_Standard_Book_Number 43 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/armstrong_numbers_test.f90: -------------------------------------------------------------------------------- 1 | program armstrong_numbers_test_main 2 | use TesterMain 3 | use armstrong_numbers 4 | 5 | implicit none 6 | 7 | ! Test 1: Zero is an Armstrong number 8 | call assert_equal(.true., isArmstrongNumber(0), "Zero is an Armstrong number") 9 | 10 | ! Test 2: Single digit numbers are Armstrong numbers 11 | call assert_equal(.true., isArmstrongNumber(5), "Single digit numbers are Armstrong numbers") 12 | 13 | ! Test 3: There are no 2 digit Armstrong numbers 14 | call assert_equal(.false., isArmstrongNumber(10), "There are no 2 digit Armstrong numbers") 15 | 16 | ! Test 4: Three digit number that is an Armstrong number 17 | call assert_equal(.true., isArmstrongNumber(153), "Three digit number that is an Armstrong number") 18 | 19 | ! Test 5: Three digit number that is not an Armstrong number 20 | call assert_equal(.false., isArmstrongNumber(100), "Three digit number that is not an Armstrong number") 21 | 22 | ! Test 6: Four digit number that is an Armstrong number 23 | call assert_equal(.true., isArmstrongNumber(9474), "Four digit number that is an Armstrong number") 24 | 25 | ! Test 7: Four digit number that is not an Armstrong number 26 | call assert_equal(.false., isArmstrongNumber(9475), "Four digit number that is not an Armstrong number") 27 | 28 | ! Test 8: Seven digit number that is an Armstrong number 29 | call assert_equal(.true., isArmstrongNumber(9926315), "Seven digit number that is an Armstrong number") 30 | 31 | ! Test 9: Seven digit number that is not an Armstrong number 32 | call assert_equal(.false., isArmstrongNumber(9926314), "Seven digit number that is not an Armstrong number") 33 | 34 | call test_report() 35 | 36 | end program 37 | 38 | -------------------------------------------------------------------------------- /exercises/practice/darts/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [9033f731-0a3a-4d9c-b1c0-34a1c8362afb] 13 | description = "Missed target" 14 | 15 | [4c9f6ff4-c489-45fd-be8a-1fcb08b4d0ba] 16 | description = "On the outer circle" 17 | 18 | [14378687-ee58-4c9b-a323-b089d5274be8] 19 | description = "On the middle circle" 20 | 21 | [849e2e63-85bd-4fed-bc3b-781ae962e2c9] 22 | description = "On the inner circle" 23 | 24 | [1c5ffd9f-ea66-462f-9f06-a1303de5a226] 25 | description = "Exactly on center" 26 | 27 | [b65abce3-a679-4550-8115-4b74bda06088] 28 | description = "Near the center" 29 | 30 | [66c29c1d-44f5-40cf-9927-e09a1305b399] 31 | description = "Just within the inner circle" 32 | 33 | [d1012f63-c97c-4394-b944-7beb3d0b141a] 34 | description = "Just outside the inner circle" 35 | 36 | [ab2b5666-b0b4-49c3-9b27-205e790ed945] 37 | description = "Just within the middle circle" 38 | 39 | [70f1424e-d690-4860-8caf-9740a52c0161] 40 | description = "Just outside the middle circle" 41 | 42 | [a7dbf8db-419c-4712-8a7f-67602b69b293] 43 | description = "Just within the outer circle" 44 | 45 | [e0f39315-9f9a-4546-96e4-a9475b885aa7] 46 | description = "Just outside the outer circle" 47 | 48 | [045d7d18-d863-4229-818e-b50828c75d19] 49 | description = "Asymmetric position between the inner and middle circles" 50 | -------------------------------------------------------------------------------- /exercises/practice/hamming/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [f6dcb64f-03b0-4b60-81b1-3c9dbf47e887] 6 | description = "empty strands" 7 | 8 | [54681314-eee2-439a-9db0-b0636c656156] 9 | description = "single letter identical strands" 10 | 11 | [294479a3-a4c8-478f-8d63-6209815a827b] 12 | description = "single letter different strands" 13 | 14 | [9aed5f34-5693-4344-9b31-40c692fb5592] 15 | description = "long identical strands" 16 | 17 | [cd2273a5-c576-46c8-a52b-dee251c3e6e5] 18 | description = "long different strands" 19 | 20 | [919f8ef0-b767-4d1b-8516-6379d07fcb28] 21 | description = "disallow first strand longer" 22 | 23 | [b9228bb1-465f-4141-b40f-1f99812de5a8] 24 | description = "disallow first strand longer" 25 | include = false 26 | 27 | [8a2d4ed0-ead5-4fdd-924d-27c4cf56e60e] 28 | description = "disallow second strand longer" 29 | 30 | [dab38838-26bb-4fff-acbe-3b0a9bfeba2d] 31 | description = "disallow second strand longer" 32 | include = false 33 | 34 | [5dce058b-28d4-4ca7-aa64-adfe4e17784c] 35 | description = "disallow left empty strand" 36 | 37 | [db92e77e-7c72-499d-8fe6-9354d2bfd504] 38 | description = "disallow left empty strand" 39 | include = false 40 | 41 | [b764d47c-83ff-4de2-ab10-6cfe4b15c0f3] 42 | description = "disallow empty first strand" 43 | include = false 44 | 45 | [38826d4b-16fb-4639-ac3e-ba027dec8b5f] 46 | description = "disallow right empty strand" 47 | 48 | [920cd6e3-18f4-4143-b6b8-74270bb8f8a3] 49 | description = "disallow right empty strand" 50 | include = false 51 | 52 | [9ab9262f-3521-4191-81f5-0ed184a5aa89] 53 | description = "disallow empty second strand" 54 | include = false 55 | -------------------------------------------------------------------------------- /exercises/practice/perfect-numbers/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [163e8e86-7bfd-4ee2-bd68-d083dc3381a3] 6 | description = "Smallest perfect number is classified correctly" 7 | 8 | [169a7854-0431-4ae0-9815-c3b6d967436d] 9 | description = "Medium perfect number is classified correctly" 10 | 11 | [ee3627c4-7b36-4245-ba7c-8727d585f402] 12 | description = "Large perfect number is classified correctly" 13 | 14 | [80ef7cf8-9ea8-49b9-8b2d-d9cb3db3ed7e] 15 | description = "Smallest abundant number is classified correctly" 16 | 17 | [3e300e0d-1a12-4f11-8c48-d1027165ab60] 18 | description = "Medium abundant number is classified correctly" 19 | 20 | [ec7792e6-8786-449c-b005-ce6dd89a772b] 21 | description = "Large abundant number is classified correctly" 22 | 23 | [e610fdc7-2b6e-43c3-a51c-b70fb37413ba] 24 | description = "Smallest prime deficient number is classified correctly" 25 | 26 | [0beb7f66-753a-443f-8075-ad7fbd9018f3] 27 | description = "Smallest non-prime deficient number is classified correctly" 28 | 29 | [1c802e45-b4c6-4962-93d7-1cad245821ef] 30 | description = "Medium deficient number is classified correctly" 31 | 32 | [47dd569f-9e5a-4a11-9a47-a4e91c8c28aa] 33 | description = "Large deficient number is classified correctly" 34 | 35 | [a696dec8-6147-4d68-afad-d38de5476a56] 36 | description = "Edge case (no factors other than itself) is classified correctly" 37 | 38 | [72445cee-660c-4d75-8506-6c40089dc302] 39 | description = "Zero is rejected (as it is not a positive integer)" 40 | 41 | [2d72ce2c-6802-49ac-8ece-c790ba3dae13] 42 | description = "Negative integer is rejected (as it is not a positive integer)" 43 | -------------------------------------------------------------------------------- /exercises/practice/leap/leap_test.f90: -------------------------------------------------------------------------------- 1 | 2 | 3 | program leap_test_main 4 | use TesterMain 5 | use leap 6 | 7 | implicit none 8 | 9 | ! Test 1: year not divisible by 4 in common year 10 | call assert_equal(.false., is_leap_year(2015),"year not divisible by 4 in common year") 11 | 12 | ! Test 2: year divisible by 2, not divisible by 4 in common year 13 | call assert_equal(.false., is_leap_year(1970), "year divisible by 2, not divisible by 4 in common year") 14 | 15 | ! Test 3: year divisible by 4, not divisible by 100 in leap year 16 | call assert_equal(.true., is_leap_year(1996), "year divisible by 4, not divisible by 100 in leap year") 17 | 18 | ! Test 4: year divisible by 4 and 5 is still a leap year 19 | call assert_equal(.true., is_leap_year(1960), "year divisible by 4 and 5 is still a leap year") 20 | 21 | ! Test 5: year divisible by 100, not divisible by 400 in common year 22 | call assert_equal(.false., is_leap_year(2100), "year divisible by 100, not divisible by 400 in common year") 23 | 24 | ! Test 6: year divisible by 100 but not by 3 is still not a leap year 25 | call assert_equal(.false., is_leap_year(1900), "year divisible by 100 but not by 3 is still not a leap year") 26 | 27 | ! Test 7: year divisible by 400 is leap year 28 | call assert_equal(.true., is_leap_year(2000), "year divisible by 400 is leap year") 29 | 30 | ! Test 8: year divisible by 400 but not by 125 is still a leap year 31 | call assert_equal(.true., is_leap_year(2400), "year divisible by 400 but not by 125 is still a leap year") 32 | 33 | ! Test 9: year divisible by 200, not divisible by 400 in common year 34 | call assert_equal(.false., is_leap_year(1800), "year divisible by 200, not divisible by 400 in common year") 35 | 36 | call test_report() 37 | 38 | end program 39 | 40 | -------------------------------------------------------------------------------- /exercises/practice/binary-search/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [b55c24a9-a98d-4379-a08c-2adcf8ebeee8] 13 | description = "finds a value in an array with one element" 14 | 15 | [73469346-b0a0-4011-89bf-989e443d503d] 16 | description = "finds a value in the middle of an array" 17 | 18 | [327bc482-ab85-424e-a724-fb4658e66ddb] 19 | description = "finds a value at the beginning of an array" 20 | 21 | [f9f94b16-fe5e-472c-85ea-c513804c7d59] 22 | description = "finds a value at the end of an array" 23 | 24 | [f0068905-26e3-4342-856d-ad153cadb338] 25 | description = "finds a value in an array of odd length" 26 | 27 | [fc316b12-c8b3-4f5e-9e89-532b3389de8c] 28 | description = "finds a value in an array of even length" 29 | 30 | [da7db20a-354f-49f7-a6a1-650a54998aa6] 31 | description = "identifies that a value is not included in the array" 32 | 33 | [95d869ff-3daf-4c79-b622-6e805c675f97] 34 | description = "a value smaller than the array's smallest value is not found" 35 | 36 | [8b24ef45-6e51-4a94-9eac-c2bf38fdb0ba] 37 | description = "a value larger than the array's largest value is not found" 38 | 39 | [f439a0fa-cf42-4262-8ad1-64bf41ce566a] 40 | description = "nothing is found in an empty array" 41 | 42 | [2c353967-b56d-40b8-acff-ce43115eed64] 43 | description = "nothing is found when the left and right bounds cross" 44 | -------------------------------------------------------------------------------- /exercises/practice/armstrong-numbers/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [c1ed103c-258d-45b2-be73-d8c6d9580c7b] 13 | description = "Zero is an Armstrong number" 14 | 15 | [579e8f03-9659-4b85-a1a2-d64350f6b17a] 16 | description = "Single-digit numbers are Armstrong numbers" 17 | 18 | [2d6db9dc-5bf8-4976-a90b-b2c2b9feba60] 19 | description = "There are no two-digit Armstrong numbers" 20 | 21 | [509c087f-e327-4113-a7d2-26a4e9d18283] 22 | description = "Three-digit number that is an Armstrong number" 23 | 24 | [7154547d-c2ce-468d-b214-4cb953b870cf] 25 | description = "Three-digit number that is not an Armstrong number" 26 | 27 | [6bac5b7b-42e9-4ecb-a8b0-4832229aa103] 28 | description = "Four-digit number that is an Armstrong number" 29 | 30 | [eed4b331-af80-45b5-a80b-19c9ea444b2e] 31 | description = "Four-digit number that is not an Armstrong number" 32 | 33 | [f971ced7-8d68-4758-aea1-d4194900b864] 34 | description = "Seven-digit number that is an Armstrong number" 35 | 36 | [7ee45d52-5d35-4fbd-b6f1-5c8cd8a67f18] 37 | description = "Seven-digit number that is not an Armstrong number" 38 | 39 | [5ee2fdf8-334e-4a46-bb8d-e5c19c02c148] 40 | description = "Armstrong number containing seven zeroes" 41 | include = false 42 | 43 | [12ffbf10-307a-434e-b4ad-c925680e1dd4] 44 | description = "The largest and last Armstrong number" 45 | include = false 46 | -------------------------------------------------------------------------------- /exercises/practice/darts/darts_test.f90: -------------------------------------------------------------------------------- 1 | ! The tests were created from https://github.com/exercism/problem-specifications/blob/main/exercises/darts/canonical-data.json 2 | 3 | program darts_test_main 4 | use TesterMain 5 | use darts 6 | implicit none 7 | 8 | ! Test 1: Missed target 9 | call assert_equal(0, score(-9.0, 9.0), "Missed target") 10 | 11 | ! Test 2: On the outer circle 12 | call assert_equal(1, score(0.0, 10.0), "On the outer circle") 13 | 14 | ! Test 3: On the middle circle 15 | call assert_equal(5, score(-5.0, 0.0), "On the middle circle") 16 | 17 | ! Test 4: On the inner circle 18 | call assert_equal(10, score(0.0, -1.0), "On the inner circle") 19 | 20 | ! Test 5: Exactly on center 21 | call assert_equal(10, score(0.0, 0.0), "Exactly on center") 22 | 23 | ! Test 6: Near the center 24 | call assert_equal(10, score(-0.1, -0.1), "Near the center") 25 | 26 | ! Test 7: Just within the inner circle 27 | call assert_equal(10, score(0.7, 0.7), "Just within the inner circle") 28 | 29 | ! Test 8: Just outside the inner circle 30 | call assert_equal(5, score(0.8, -0.8), "Just outside the inner circle") 31 | 32 | ! Test 9: Just within the middle circle 33 | call assert_equal(5, score(-3.5, 3.5), "Just within the middle circle") 34 | 35 | ! Test 10: Just outside the middle circle 36 | call assert_equal(1, score(-3.6, -3.6), "Just outside the middle circle") 37 | 38 | ! Test 11: Just within the outer circle 39 | call assert_equal(1, score(-7.0, 7.0), "Just within the outer circle") 40 | 41 | ! Test 12: Just outside the outer circle 42 | call assert_equal(0, score(7.1, -7.1), "Just outside the outer circle") 43 | 44 | ! Test 13: Asymmetric position between the inner and middle circles 45 | call assert_equal(5, score(0.5, -4.0), "Asymmetric position between the inner and middle circles") 46 | 47 | call test_report() 48 | 49 | end program 50 | -------------------------------------------------------------------------------- /exercises/practice/protein-translation/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module protein_translation 2 | implicit none 3 | 4 | character(len=13), parameter, private :: protein_names(7) = [& 5 | "Methionine ", & 6 | "Phenylalanine", & 7 | "Leucine ", & 8 | "Serine ", & 9 | "Tyrosine ", & 10 | "Cysteine ", & 11 | "Tryptophan " & 12 | ] 13 | 14 | contains 15 | 16 | function proteins(rna) result(names) 17 | character(len=*), intent(in) :: rna 18 | integer, allocatable :: protein_ids(:) 19 | character(len=13), allocatable :: names(:) 20 | integer :: i, n_protein, max_n_proteins 21 | 22 | max_n_proteins = len(rna)/3 23 | allocate(protein_ids(0:max_n_proteins-1)) 24 | 25 | n_protein = 0 26 | do i = 1, len(rna), 3 27 | if (i + 2 > len(rna)) then 28 | n_protein = 0 29 | exit ! Invalid codon 30 | end if 31 | select case (rna(i:i+2)) 32 | case ("AUG") 33 | protein_ids(n_protein+1) = 1 34 | case ("UUU", "UUC") 35 | protein_ids(n_protein+1) = 2 36 | case ("UUA", "UUG") 37 | protein_ids(n_protein+1) = 3 38 | case ("UCU", "UCC", "UCA", "UCG") 39 | protein_ids(n_protein+1) = 4 40 | case ("UAU", "UAC") 41 | protein_ids(n_protein+1) = 5 42 | case ("UGU", "UGC") 43 | protein_ids(n_protein+1) = 6 44 | case ("UGG") 45 | protein_ids(n_protein+1) = 7 46 | case ("UAA", "UAG", "UGA") 47 | exit ! stop codon 48 | case default 49 | n_protein = 0 50 | exit ! invalid codon 51 | end select 52 | n_protein = n_protein + 1 53 | end do 54 | 55 | allocate(names(n_protein)) 56 | do i = 1, n_protein 57 | names(i) = protein_names(protein_ids(i)) 58 | end do 59 | 60 | end function proteins 61 | 62 | end module protein_translation 63 | 64 | -------------------------------------------------------------------------------- /exercises/practice/roman-numerals/.docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Today, most people in the world use Arabic numerals (0–9). 4 | But if you travelled back two thousand years, you'd find that most Europeans were using Roman numerals instead. 5 | 6 | To write a Roman numeral we use the following Latin letters, each of which has a value: 7 | 8 | | M | D | C | L | X | V | I | 9 | | ---- | --- | --- | --- | --- | --- | --- | 10 | | 1000 | 500 | 100 | 50 | 10 | 5 | 1 | 11 | 12 | A Roman numeral is a sequence of these letters, and its value is the sum of the letters' values. 13 | For example, `XVIII` has the value 18 (`10 + 5 + 1 + 1 + 1 = 18`). 14 | 15 | 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**. 16 | That means that we can't express numbers such as 4 with the seemingly natural `IIII`. 17 | Instead, for those numbers, we use a subtraction method between two letters. 18 | So we think of `4` not as `1 + 1 + 1 + 1` but instead as `5 - 1`. 19 | And slightly confusingly to our modern thinking, we write the smaller number first. 20 | This applies only in the following cases: 4 (`IV`), 9 (`IX`), 40 (`XL`), 90 (`XC`), 400 (`CD`) and 900 (`CM`). 21 | 22 | Order matters in Roman numerals! 23 | Letters (and the special compounds above) must be ordered by decreasing value from left to right. 24 | 25 | Here are some examples: 26 | 27 | ```text 28 | 105 => CV 29 | ---- => -- 30 | 100 => C 31 | + 5 => V 32 | ``` 33 | 34 | ```text 35 | 106 => CVI 36 | ---- => -- 37 | 100 => C 38 | + 5 => V 39 | + 1 => I 40 | ``` 41 | 42 | ```text 43 | 104 => CIV 44 | ---- => --- 45 | 100 => C 46 | + 4 => IV 47 | ``` 48 | 49 | And a final more complex example: 50 | 51 | ```text 52 | 1996 => MCMXCVI 53 | ----- => ------- 54 | 1000 => M 55 | + 900 => CM 56 | + 90 => XC 57 | + 5 => V 58 | + 1 => I 59 | ``` 60 | -------------------------------------------------------------------------------- /exercises/practice/matrix/matrix_test.f90: -------------------------------------------------------------------------------- 1 | program matrix_test_main 2 | 3 | use TesterMain 4 | use matrix 5 | 6 | implicit none 7 | 8 | ! Test 1: extract row from one number matrix 9 | !!call assert_equal_int_arr(1, row(1, 1), "extract row from one number matrix") 10 | ! Test 2: can extract row 11 | call assert_equal((/3, 4/), row( (/"1, 2", "3, 4"/), (/ 2, 2 /), 2), "can extract row") 12 | 13 | ! Test 3: extract row where numbers have different widths 14 | call assert_equal((/10, 20/), row( (/"1, 2 ", "10, 20"/), (/ 2, 2 /), 2), & 15 | & "extract row where numbers have different widths") 16 | ! Test 4: can extract row from non-square matrix with no corresponding column 17 | call assert_equal((/8, 7, 6/), row( & 18 | & (/"1, 2, 3", & 19 | & "4, 5, 6", & 20 | & "7, 8, 9", & 21 | & "8, 7, 6"/), (/ 4, 3 /), 4), & 22 | & "can extract row from non-square matrix with no corresponding column") 23 | ! Test 5: extract column from one number matrix 24 | !!call assert_equal_int_arr(1, column(1, 1), "extract column from one number matrix") 25 | ! Test 6: can extract column 26 | call assert_equal((/3, 6, 9/), column( & 27 | & (/"1, 2, 3", & 28 | & "4, 5, 6", & 29 | & "7, 8, 9"/), (/3, 3/), 3), & 30 | & "can extract column") 31 | ! Test 7: can extract column from non-square matrix with no corresponding row 32 | call assert_equal((/4, 8, 6/), column( & 33 | & (/"1, 2, 3, 4", & 34 | & "5, 6, 7, 8", & 35 | & "9, 8, 7, 6"/), (/3,4/), 4), & 36 | & "can extract column from non-square matrix with no corresponding row") 37 | ! Test 8: extract column where numbers have different widths 38 | call assert_equal((/1903, 3, 479/), column( & 39 | & (/"89, 1903, 3", & 40 | & "18, 3, 1 ", & 41 | & "9, 479, 800"/), (/3,3/), 2), & 42 | & "extract column where numbers have different widths") 43 | 44 | call test_report() 45 | 46 | end program 47 | 48 | -------------------------------------------------------------------------------- /exercises/practice/luhn/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Determine whether a number is valid according to the [Luhn formula][luhn]. 4 | 5 | The number will be provided as a string. 6 | 7 | ## Validating a number 8 | 9 | Strings of length 1 or less are not valid. 10 | Spaces are allowed in the input, but they should be stripped before checking. 11 | All other non-digit characters are disallowed. 12 | 13 | ## Examples 14 | 15 | ### Valid credit card number 16 | 17 | The number to be checked is `4539 3195 0343 6467`. 18 | 19 | The first step of the Luhn algorithm is to start at the end of the number and double every second digit, beginning with the second digit from the right and moving left. 20 | 21 | ```text 22 | 4539 3195 0343 6467 23 | ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ (double these) 24 | ``` 25 | 26 | If the result of doubling a digit is greater than 9, we subtract 9 from that result. 27 | We end up with: 28 | 29 | ```text 30 | 8569 6195 0383 3437 31 | ``` 32 | 33 | Finally, we sum all digits. 34 | If the sum is evenly divisible by 10, the original number is valid. 35 | 36 | ```text 37 | 8 + 5 + 6 + 9 + 6 + 1 + 9 + 5 + 0 + 3 + 8 + 3 + 3 + 4 + 3 + 7 = 80 38 | ``` 39 | 40 | 80 is evenly divisible by 10, so number `4539 3195 0343 6467` is valid! 41 | 42 | ### Invalid Canadian SIN 43 | 44 | The number to be checked is `066 123 468`. 45 | 46 | We start at the end of the number and double every second digit, beginning with the second digit from the right and moving left. 47 | 48 | ```text 49 | 066 123 478 50 | ↑ ↑ ↑ ↑ (double these) 51 | ``` 52 | 53 | If the result of doubling a digit is greater than 9, we subtract 9 from that result. 54 | We end up with: 55 | 56 | ```text 57 | 036 226 458 58 | ``` 59 | 60 | We sum the digits: 61 | 62 | ```text 63 | 0 + 3 + 6 + 2 + 2 + 6 + 4 + 5 + 8 = 36 64 | ``` 65 | 66 | 36 is not evenly divisible by 10, so number `066 123 478` is not valid! 67 | 68 | [luhn]: https://en.wikipedia.org/wiki/Luhn_algorithm 69 | -------------------------------------------------------------------------------- /exercises/practice/linked-list/linked_list.f90: -------------------------------------------------------------------------------- 1 | module linked_list 2 | implicit none 3 | 4 | type :: list_t 5 | integer :: placeholder ! Replace this line in your implementation 6 | end type list_t 7 | 8 | contains 9 | 10 | function new() result(list) 11 | type(list_t) :: list 12 | 13 | list%placeholder = -1 ! Replace this line in your implementation 14 | end function new 15 | 16 | subroutine push(list, val) 17 | type(list_t), intent(inout) :: list 18 | integer, intent(in) :: val 19 | 20 | list%placeholder = list%placeholder + val ! Replace this line in your implementation 21 | end subroutine push 22 | 23 | function pop(list) result(val) 24 | type(list_t), intent(inout) :: list 25 | integer :: val 26 | 27 | val = list%placeholder ! Replace this line in your implementation 28 | end function pop 29 | 30 | subroutine unshift(list, val) 31 | type(list_t), intent(inout) :: list 32 | integer, intent(in) :: val 33 | 34 | list%placeholder = list%placeholder + val ! Replace this line in your implementation 35 | end subroutine unshift 36 | 37 | function shift(list) result(val) 38 | type(list_t), intent(inout) :: list 39 | integer :: val 40 | 41 | val = list%placeholder ! Replace this line in your implementation 42 | end function shift 43 | 44 | function length(list) result(n) 45 | type(list_t), intent(in) :: list 46 | integer :: n 47 | 48 | n = list%placeholder ! Replace this line in your implementation 49 | end function length 50 | 51 | subroutine delete(list, val) 52 | type(list_t), intent(inout) :: list 53 | integer :: val 54 | 55 | list%placeholder = list%placeholder + val ! Replace this line in your implementation 56 | end subroutine delete 57 | 58 | subroutine destroy(list) 59 | type(list_t), intent(inout) :: list 60 | 61 | list = list ! Replace this line in your implementation 62 | end subroutine destroy 63 | 64 | end module 65 | -------------------------------------------------------------------------------- /exercises/practice/high-scores/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [1035eb93-2208-4c22-bab8-fef06769a73c] 13 | description = "List of scores" 14 | 15 | [6aa5dbf5-78fa-4375-b22c-ffaa989732d2] 16 | description = "Latest score" 17 | 18 | [b661a2e1-aebf-4f50-9139-0fb817dd12c6] 19 | description = "Personal best" 20 | 21 | [3d996a97-c81c-4642-9afc-80b80dc14015] 22 | description = "Top 3 scores -> Personal top three from a list of scores" 23 | 24 | [1084ecb5-3eb4-46fe-a816-e40331a4e83a] 25 | description = "Top 3 scores -> Personal top highest to lowest" 26 | 27 | [e6465b6b-5a11-4936-bfe3-35241c4f4f16] 28 | description = "Top 3 scores -> Personal top when there is a tie" 29 | 30 | [f73b02af-c8fd-41c9-91b9-c86eaa86bce2] 31 | description = "Top 3 scores -> Personal top when there are less than 3" 32 | 33 | [16608eae-f60f-4a88-800e-aabce5df2865] 34 | description = "Top 3 scores -> Personal top when there is only one" 35 | 36 | [2df075f9-fec9-4756-8f40-98c52a11504f] 37 | description = "Top 3 scores -> Latest score after personal top scores" 38 | include = false 39 | 40 | [809c4058-7eb1-4206-b01e-79238b9b71bc] 41 | description = "Top 3 scores -> Scores after personal top scores" 42 | include = false 43 | 44 | [ddb0efc0-9a86-4f82-bc30-21ae0bdc6418] 45 | description = "Top 3 scores -> Latest score after personal best" 46 | include = false 47 | 48 | [6a0fd2d1-4cc4-46b9-a5bb-2fb667ca2364] 49 | description = "Top 3 scores -> Scores after personal best" 50 | include = false 51 | -------------------------------------------------------------------------------- /exercises/practice/protein-translation/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Translate RNA sequences into proteins. 4 | 5 | RNA can be broken into three-nucleotide sequences called codons, and then translated to a protein like so: 6 | 7 | RNA: `"AUGUUUUCU"` => translates to 8 | 9 | Codons: `"AUG", "UUU", "UCU"` 10 | => which become a protein with the following sequence => 11 | 12 | Protein: `"Methionine", "Phenylalanine", "Serine"` 13 | 14 | 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. 15 | If it works for one codon, the program should work for all of them. 16 | However, feel free to expand the list in the test suite to include them all. 17 | 18 | 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. 19 | 20 | All subsequent codons after are ignored, like this: 21 | 22 | RNA: `"AUGUUUUCUUAAAUG"` => 23 | 24 | Codons: `"AUG", "UUU", "UCU", "UAA", "AUG"` => 25 | 26 | Protein: `"Methionine", "Phenylalanine", "Serine"` 27 | 28 | Note the stop codon `"UAA"` terminates the translation and the final methionine is not translated into the protein sequence. 29 | 30 | Below are the codons and resulting amino acids needed for the exercise. 31 | 32 | | Codon | Amino Acid | 33 | | :----------------- | :------------ | 34 | | AUG | Methionine | 35 | | UUU, UUC | Phenylalanine | 36 | | UUA, UUG | Leucine | 37 | | UCU, UCC, UCA, UCG | Serine | 38 | | UAU, UAC | Tyrosine | 39 | | UGU, UGC | Cysteine | 40 | | UGG | Tryptophan | 41 | | UAA, UAG, UGA | STOP | 42 | 43 | Learn more about [protein translation on Wikipedia][protein-translation]. 44 | 45 | [protein-translation]: https://en.wikipedia.org/wiki/Translation_(biology) 46 | -------------------------------------------------------------------------------- /exercises/practice/queen-attack/queen_attack_test.f90: -------------------------------------------------------------------------------- 1 | program queen_attack_test_main 2 | use TesterMain 3 | use queen_attack 4 | 5 | implicit none 6 | 7 | ! Test 1: queen with a valid position 8 | call assert_equal(.true., isValid([2, 2]), "queen with a valid position") 9 | 10 | ! Test 2: queen must have positive row 11 | ! ERROR: row not positive 12 | call assert_equal(.false., isValid([-2, 2]), "queen must have positive row") 13 | 14 | ! Test 3: queen must have row on board 15 | ! ERROR: row not on board 16 | call assert_equal(.false., isValid([9, 4]), "queen must have row on board") 17 | 18 | ! Test 4: queen must have positive column 19 | ! ERROR: column not positive 20 | call assert_equal(.false., isValid([2, -2]), "queen must have positive column") 21 | 22 | ! Test 5: queen must have column on board 23 | ! ERROR: column not on board 24 | call assert_equal(.false., isValid([4, 9]), "queen must have column on board") 25 | 26 | ! Test 6: cannot attack 27 | call assert_equal(.false., canAttack([2, 4], [6, 6]), "cannot attack") 28 | 29 | ! Test 7: can attack on same row 30 | call assert_equal(.true., canAttack([2, 4], [2, 6]), "can attack on same row") 31 | 32 | ! Test 8: can attack on same column 33 | call assert_equal(.true., canAttack([4, 5], [2, 5]), "can attack on same column") 34 | 35 | ! Test 9: can attack on first diagonal 36 | call assert_equal(.true., canAttack([3, 3], [1, 5]), "can attack on first diagonal") 37 | 38 | ! Test 10: can attack on second diagonal 39 | call assert_equal(.true., canAttack([2, 2], [3, 1]), "can attack on second diagonal") 40 | 41 | ! Test 11: can attack on third diagonal 42 | call assert_equal(.true., canAttack([2, 2], [1, 1]), "can attack on third diagonal") 43 | 44 | ! Test 12: can attack on fourth diagonal 45 | call assert_equal(.true., canAttack([2, 8], [1, 7]), "can attack on fourth diagonal") 46 | 47 | call test_report() 48 | 49 | end program 50 | 51 | -------------------------------------------------------------------------------- /exercises/practice/darts/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Calculate the points scored in a single toss of a Darts game. 4 | 5 | [Darts][darts] is a game where players throw darts at a [target][darts-target]. 6 | 7 | In our particular instance of the game, the target rewards 4 different amounts of points, depending on where the dart lands: 8 | 9 | ![Our dart scoreboard with values from a complete miss to a bullseye](https://assets.exercism.org/images/exercises/darts/darts-scoreboard.svg) 10 | 11 | - If the dart lands outside the target, player earns no points (0 points). 12 | - If the dart lands in the outer circle of the target, player earns 1 point. 13 | - If the dart lands in the middle circle of the target, player earns 5 points. 14 | - If the dart lands in the inner circle of the target, player earns 10 points. 15 | 16 | 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. 17 | Of course, they are all centered at the same point — that is, the circles are [concentric][] defined by the coordinates (0, 0). 18 | 19 | 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. 20 | 21 | ## Credit 22 | 23 | The scoreboard image was created by [habere-et-dispertire][habere-et-dispertire] using [Inkscape][inkscape]. 24 | 25 | [darts]: https://en.wikipedia.org/wiki/Darts 26 | [darts-target]: https://en.wikipedia.org/wiki/Darts#/media/File:Darts_in_a_dartboard.jpg 27 | [concentric]: https://mathworld.wolfram.com/ConcentricCircles.html 28 | [cartesian-coordinates]: https://www.mathsisfun.com/data/cartesian-coordinates.html 29 | [real-numbers]: https://www.mathsisfun.com/numbers/real-numbers.html 30 | [habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire 31 | [inkscape]: https://en.wikipedia.org/wiki/Inkscape 32 | -------------------------------------------------------------------------------- /exercises/practice/isogram/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [a0e97d2d-669e-47c7-8134-518a1e2c4555] 13 | description = "empty string" 14 | 15 | [9a001b50-f194-4143-bc29-2af5ec1ef652] 16 | description = "isogram with only lower case characters" 17 | 18 | [8ddb0ca3-276e-4f8b-89da-d95d5bae78a4] 19 | description = "word with one duplicated character" 20 | 21 | [6450b333-cbc2-4b24-a723-0b459b34fe18] 22 | description = "word with one duplicated character from the end of the alphabet" 23 | 24 | [a15ff557-dd04-4764-99e7-02cc1a385863] 25 | description = "longest reported english isogram" 26 | 27 | [f1a7f6c7-a42f-4915-91d7-35b2ea11c92e] 28 | description = "word with duplicated character in mixed case" 29 | 30 | [14a4f3c1-3b47-4695-b645-53d328298942] 31 | description = "word with duplicated character in mixed case, lowercase first" 32 | 33 | [423b850c-7090-4a8a-b057-97f1cadd7c42] 34 | description = "hypothetical isogrammic word with hyphen" 35 | 36 | [93dbeaa0-3c5a-45c2-8b25-428b8eacd4f2] 37 | description = "hypothetical word with duplicated character following hyphen" 38 | 39 | [36b30e5c-173f-49c6-a515-93a3e825553f] 40 | description = "isogram with duplicated hyphen" 41 | 42 | [cdabafa0-c9f4-4c1f-b142-689c6ee17d93] 43 | description = "made-up name that is an isogram" 44 | 45 | [5fc61048-d74e-48fd-bc34-abfc21552d4d] 46 | description = "duplicated character in the middle" 47 | 48 | [310ac53d-8932-47bc-bbb4-b2b94f25a83e] 49 | description = "same first and last characters" 50 | 51 | [0d0b8644-0a1e-4a31-a432-2b3ee270d847] 52 | description = "word with duplicated character and with two hyphens" 53 | -------------------------------------------------------------------------------- /exercises/practice/space-age/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module orbital_constants 3 | implicit none 4 | 5 | ! Earth: orbital period 1.0 Earth years, 365.25 Earth days, or 31557600 seconds 6 | double precision, parameter, public :: earth_year_seconds = 31557600.d0 7 | 8 | ! A planet's orbit as measured in Earth years 9 | double precision, parameter, public :: mercury_earth_years = 0.2408467d0 10 | double precision, parameter, public :: venus_earth_years = 0.61519726d0 11 | double precision, parameter, public :: mars_earth_years = 1.8808158d0 12 | double precision, parameter, public :: jupiter_earth_years = 11.862615d0 13 | double precision, parameter, public :: saturn_earth_years = 29.447498d0 14 | double precision, parameter, public :: uranus_earth_years = 84.016846d0 15 | double precision, parameter, public :: neptune_earth_years = 164.79132d0 16 | 17 | end module orbital_constants 18 | 19 | module space_age 20 | use orbital_constants 21 | implicit none 22 | contains 23 | 24 | double precision function age_in_years(planet, seconds) 25 | character(len=*), intent(in) :: planet 26 | double precision, intent(in) :: seconds 27 | 28 | ! A multiplier for a number of Earth years for the given planet 29 | double precision :: n_earth_years = 1.d0 30 | 31 | age_in_years = 0.d0 32 | 33 | select case (planet) 34 | case ("Mercury") 35 | n_earth_years = mercury_earth_years 36 | case ("Venus") 37 | n_earth_years = venus_earth_years 38 | case ("Earth") 39 | n_earth_years = 1.d0 40 | case ("Mars") 41 | n_earth_years = mars_earth_years 42 | case ("Jupiter") 43 | n_earth_years = jupiter_earth_years 44 | case ("Saturn") 45 | n_earth_years = saturn_earth_years 46 | case ("Uranus") 47 | n_earth_years = uranus_earth_years 48 | case ("Neptune") 49 | n_earth_years = neptune_earth_years 50 | case default 51 | write(*,*) 'ERROR: unknown planet: '//trim(planet) 52 | end select 53 | 54 | age_in_years = seconds / earth_year_seconds / n_earth_years 55 | 56 | end function 57 | 58 | end module 59 | -------------------------------------------------------------------------------- /config/exercise_readme.go.tmpl: -------------------------------------------------------------------------------- 1 | # {{ .Spec.Name }} 2 | 3 | {{ .Spec.Description -}} 4 | {{- with .Hints }} 5 | {{ . }} 6 | {{ end }} 7 | {{ with .Spec.Credits }} 8 | ## Source 9 | 10 | {{ . }} 11 | {{ end }} 12 | ## Getting Started 13 | 14 | Make sure you have read the [Installation](https://exercism.io/tracks/fortran/installation) and [Running the tests](https://exercism.io/tracks/fortran/tests) pages for Fortran on exercism.io. 15 | This covers the basic information on setting up the development environment expected by the exercises. 16 | 17 | ## Passing the tests 18 | 19 | Get the first test compiling, linking and passing by following the [three rules of test-driven development](http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd). 20 | 21 | The tests are in `{{ .Spec.SnakeCaseName -}}_test.f90` and they expect the implementation to be in `{{ .Spec.SnakeCaseName -}}.f90`. 22 | In case the file `{{ .Spec.SnakeCaseName -}}.f90` does not exist, create the file with the content: 23 | 24 | ```c 25 | module {{ .Spec.SnakeCaseName }} 26 | implicit none 27 | contains 28 | 29 | ! Create your function here 30 | 31 | end module {{ .Spec.SnakeCaseName }} 32 | ``` 33 | 34 | Now create a build directory (eg. `mkdir build`), change into it and run `cmake ..` to configure the build. 35 | 36 | Note, that the first time you call `cmake ..` it will download the `testlib` automatically which is used in `{{ .Spec.SnakeCaseName -}}_test.f90`. 37 | 38 | The `testib` can also be downloaded manually from github. For more information see [Running the tests](https://exercism.io/tracks/fortran/tests). 39 | 40 | Now build (eg. `make`) and run tests with `ctest -V`. For a detailed description see [Running the Tests](https://exercism.io/tracks/fortran/tests). 41 | 42 | At first all test will fail. 43 | To disable a certain test, simply comment it out with '!', eg. 44 | 45 | ```c 46 | ! Test 16: non-letters with question 47 | ! call assert_equal("Sure.", hey(":) ?"), "non-letters with question") 48 | ``` 49 | 50 | ## Submitting Incomplete Solutions 51 | It's possible to submit an incomplete solution so you can see how others have completed the exercise. 52 | -------------------------------------------------------------------------------- /exercises/practice/yacht/.docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Instructions 2 | 3 | Given five dice and a category, calculate the score of the dice for that category. 4 | 5 | ~~~~exercism/note 6 | You'll always be presented with five dice. 7 | Each dice's value will be between one and six inclusively. 8 | The dice may be unordered. 9 | ~~~~ 10 | 11 | ## Scores in Yacht 12 | 13 | | Category | Score | Description | Example | 14 | | --------------- | ---------------------- | ---------------------------------------- | ------------------- | 15 | | Ones | 1 × number of ones | Any combination | 1 1 1 4 5 scores 3 | 16 | | Twos | 2 × number of twos | Any combination | 2 2 3 4 5 scores 4 | 17 | | Threes | 3 × number of threes | Any combination | 3 3 3 3 3 scores 15 | 18 | | Fours | 4 × number of fours | Any combination | 1 2 3 3 5 scores 0 | 19 | | Fives | 5 × number of fives | Any combination | 5 1 5 2 5 scores 15 | 20 | | Sixes | 6 × number of sixes | Any combination | 2 3 4 5 6 scores 6 | 21 | | Full House | Total of the dice | Three of one number and two of another | 3 3 3 5 5 scores 19 | 22 | | Four of a Kind | Total of the four dice | At least four dice showing the same face | 4 4 4 4 6 scores 16 | 23 | | Little Straight | 30 points | 1-2-3-4-5 | 1 2 3 4 5 scores 30 | 24 | | Big Straight | 30 points | 2-3-4-5-6 | 2 3 4 5 6 scores 30 | 25 | | Choice | Sum of the dice | Any combination | 2 3 3 4 6 scores 18 | 26 | | Yacht | 50 points | All five dice showing the same face | 4 4 4 4 4 scores 50 | 27 | 28 | If the dice do **not** satisfy the requirements of a category, the score is zero. 29 | If, for example, _Four Of A Kind_ is entered in the _Yacht_ category, zero points are scored. 30 | A _Yacht_ scores zero if entered in the _Full House_ category. 31 | -------------------------------------------------------------------------------- /exercises/practice/hamming/hamming_test.f90: -------------------------------------------------------------------------------- 1 | program hamming_test_main 2 | use TesterMain 3 | use hamming 4 | 5 | implicit none 6 | 7 | integer distance 8 | 9 | ! Test 1: empty strands 10 | call assert_equal(.true., compute("", "", distance), "empty strands") 11 | call assert_equal(0, distance, "empty strands, distance=0") 12 | 13 | ! Test 2: single letter identical strands 14 | call assert_equal(.true., compute("A", "A", distance), "single letter identical strands") 15 | call assert_equal(0, distance,"single letter identical strands, distance=0") 16 | 17 | ! Test 3: single letter different strands 18 | call assert_equal(.true., compute("G", "T", distance), "single letter different strands") 19 | call assert_equal(1, distance, "single letter different strands, distance=1") 20 | 21 | ! Test 4: long identical strands 22 | call assert_equal(.true., compute("GGACTGAAATCTG", "GGACTGAAATCTG", distance), "long identical strands") 23 | call assert_equal(0, distance, "single letter different strands, distance=0") 24 | 25 | ! Test 5: long different strands 26 | call assert_equal(.true., compute("GGACGGATTCTG", "AGGACGGATTCT", distance), "long different strands") 27 | call assert_equal(9, distance,"long different strands, distance=9") 28 | 29 | ! Test 6: disallow first strand longer 30 | call assert_equal(.false., compute("AATG", "AAA", distance), "disallow first strand longer") 31 | call assert_equal(0, distance,"disallow first strand longer, distance=0") 32 | 33 | ! Test 7: disallow second strand longer 34 | call assert_equal(.false., compute("ATA", "AGTG", distance), "disallow second strand longer") 35 | call assert_equal(0, distance,"disallow second strand longer, distance=0") 36 | 37 | ! Test 8: disallow left empty strand 38 | call assert_equal(.false., compute("", "G", distance), "disallow left empty strand") 39 | call assert_equal(0, distance,"disallow left empty strand, distance=0") 40 | 41 | ! Test 9: disallow right empty strand 42 | call assert_equal(.false., compute("G", "", distance), "disallow right empty strand") 43 | call assert_equal(0, distance,"disallow right empty strand, distance=0") 44 | 45 | call test_report() 46 | 47 | end program 48 | 49 | -------------------------------------------------------------------------------- /exercises/practice/sum-of-multiples/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [54aaab5a-ce86-4edc-8b40-d3ab2400a279] 13 | description = "no multiples within limit" 14 | 15 | [361e4e50-c89b-4f60-95ef-5bc5c595490a] 16 | description = "one factor has multiples within limit" 17 | 18 | [e644e070-040e-4ae0-9910-93c69fc3f7ce] 19 | description = "more than one multiple within limit" 20 | 21 | [607d6eb9-535c-41ce-91b5-3a61da3fa57f] 22 | description = "more than one factor with multiples within limit" 23 | 24 | [f47e8209-c0c5-4786-b07b-dc273bf86b9b] 25 | description = "each multiple is only counted once" 26 | 27 | [28c4b267-c980-4054-93e9-07723db615ac] 28 | description = "a much larger limit" 29 | 30 | [09c4494d-ff2d-4e0f-8421-f5532821ee12] 31 | description = "three factors" 32 | 33 | [2d0d5faa-f177-4ad6-bde9-ebb865083751] 34 | description = "factors not relatively prime" 35 | 36 | [ece8f2e8-96aa-4166-bbb7-6ce71261e354] 37 | description = "some pairs of factors relatively prime and some not" 38 | 39 | [624fdade-6ffb-400e-8472-456a38c171c0] 40 | description = "one factor is a multiple of another" 41 | 42 | [949ee7eb-db51-479c-b5cb-4a22b40ac057] 43 | description = "much larger factors" 44 | 45 | [41093673-acbd-482c-ab80-d00a0cbedecd] 46 | description = "all numbers are multiples of 1" 47 | 48 | [1730453b-baaa-438e-a9c2-d754497b2a76] 49 | description = "no factors means an empty sum" 50 | 51 | [214a01e9-f4bf-45bb-80f1-1dce9fbb0310] 52 | description = "the only multiple of 0 is 0" 53 | 54 | [c423ae21-a0cb-4ec7-aeb1-32971af5b510] 55 | description = "the factor 0 does not affect the sum of multiples of other factors" 56 | 57 | [17053ba9-112f-4ac0-aadb-0519dd836342] 58 | description = "solutions using include-exclude must extend to cardinality greater than 3" 59 | -------------------------------------------------------------------------------- /exercises/practice/bob/.meta/example.f90: -------------------------------------------------------------------------------- 1 | module bob 2 | implicit none 3 | 4 | character(len=1), parameter :: CARRIAGE_RETURN_CHAR = char(13) 5 | character(len=1), parameter :: NEWLINE_CHAR = char(10) 6 | character(len=1), parameter :: TAB_CHAR = char(9) 7 | 8 | contains 9 | function is_uppercase(str) 10 | logical :: is_uppercase 11 | character(len=*),intent(in) :: str 12 | character :: chr 13 | integer :: i 14 | is_uppercase = .FALSE. 15 | do i = 1,len_trim(str) 16 | chr = str(i:i) 17 | if (chr >= 'a' .AND. chr <= 'z') then 18 | is_uppercase = .FALSE. 19 | return 20 | else if (chr >= 'A' .AND. chr <= 'Z') then 21 | is_uppercase = .TRUE. 22 | end if 23 | end do 24 | end function is_uppercase 25 | 26 | function is_question(str) 27 | logical :: is_question 28 | character(*) :: str 29 | character :: chr 30 | integer :: i 31 | do i = len(str), 1, -1 32 | chr = str(i:i) 33 | if (chr /= ' ' .and. chr /= TAB_CHAR .and. & 34 | chr /= NEWLINE_CHAR .and. chr /= CARRIAGE_RETURN_CHAR) then 35 | is_question = (chr .EQ. '?') 36 | return 37 | end if 38 | end do 39 | is_question = .false. 40 | end function is_question 41 | 42 | function is_blank(str) 43 | logical :: is_blank 44 | character(*) :: str 45 | character :: chr 46 | integer :: i 47 | is_blank = .TRUE. 48 | do i = 1, len(str) 49 | if (chr /= ' ' .and. chr /= TAB_CHAR .and. & 50 | chr /= NEWLINE_CHAR .and. chr /= CARRIAGE_RETURN_CHAR) then 51 | is_blank = .FALSE. 52 | return 53 | end if 54 | end do 55 | end function is_blank 56 | 57 | function hey(statement) 58 | character(100) :: hey 59 | character(len=*), intent(in) :: statement 60 | 61 | if ( is_uppercase(statement) .and.is_question(statement) ) then 62 | hey = "Calm down, I know what I'm doing!" 63 | else if ( is_uppercase(statement) ) then 64 | hey = 'Whoa, chill out!' 65 | else if ( is_question(statement) ) then 66 | hey = 'Sure.' 67 | else if ( is_blank(statement) ) then 68 | hey = 'Fine. Be that way!' 69 | else 70 | hey = 'Whatever.' 71 | end if 72 | 73 | end function hey 74 | end module bob 75 | -------------------------------------------------------------------------------- /exercises/practice/raindrops/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. Regular comments will be removed when this 2 | # file is regenerated. Regenerating will not touch any manually added keys, 3 | # so comments can be added in a "comment" key. 4 | 5 | [1575d549-e502-46d4-a8e1-6b7bec6123d8] 6 | description = "the sound for 1 is 1" 7 | 8 | [1f51a9f9-4895-4539-b182-d7b0a5ab2913] 9 | description = "the sound for 3 is Pling" 10 | 11 | [2d9bfae5-2b21-4bcd-9629-c8c0e388f3e0] 12 | description = "the sound for 5 is Plang" 13 | 14 | [d7e60daa-32ef-4c23-b688-2abff46c4806] 15 | description = "the sound for 7 is Plong" 16 | 17 | [6bb4947b-a724-430c-923f-f0dc3d62e56a] 18 | description = "the sound for 6 is Pling as it has a factor 3" 19 | 20 | [ce51e0e8-d9d4-446d-9949-96eac4458c2d] 21 | description = "2 to the power 3 does not make a raindrop sound as 3 is the exponent not the base" 22 | 23 | [0dd66175-e3e2-47fc-8750-d01739856671] 24 | description = "the sound for 9 is Pling as it has a factor 3" 25 | 26 | [022c44d3-2182-4471-95d7-c575af225c96] 27 | description = "the sound for 10 is Plang as it has a factor 5" 28 | 29 | [37ab74db-fed3-40ff-b7b9-04acdfea8edf] 30 | description = "the sound for 14 is Plong as it has a factor of 7" 31 | 32 | [31f92999-6afb-40ee-9aa4-6d15e3334d0f] 33 | description = "the sound for 15 is PlingPlang as it has factors 3 and 5" 34 | 35 | [ff9bb95d-6361-4602-be2c-653fe5239b54] 36 | description = "the sound for 21 is PlingPlong as it has factors 3 and 7" 37 | 38 | [d2e75317-b72e-40ab-8a64-6734a21dece1] 39 | description = "the sound for 25 is Plang as it has a factor 5" 40 | 41 | [a09c4c58-c662-4e32-97fe-f1501ef7125c] 42 | description = "the sound for 27 is Pling as it has a factor 3" 43 | 44 | [bdf061de-8564-4899-a843-14b48b722789] 45 | description = "the sound for 35 is PlangPlong as it has factors 5 and 7" 46 | 47 | [c4680bee-69ba-439d-99b5-70c5fd1a7a83] 48 | description = "the sound for 49 is Plong as it has a factor 7" 49 | 50 | [17f2bc9a-b65a-4d23-8ccd-266e8c271444] 51 | description = "the sound for 52 is 52" 52 | 53 | [e46677ed-ff1a-419f-a740-5c713d2830e4] 54 | description = "the sound for 105 is PlingPlangPlong as it has factors 3, 5 and 7" 55 | 56 | [13c6837a-0fcd-4b86-a0eb-20572f7deb0b] 57 | description = "the sound for 3125 is Plang as it has a factor 5" 58 | -------------------------------------------------------------------------------- /exercises/practice/allergies/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module allergies 3 | implicit none 4 | 5 | integer, parameter :: ALLERGY_TYPES_LEN = 8 6 | 7 | integer, parameter :: unknown = 0 8 | integer, parameter :: eggs = 1 9 | integer, parameter :: peanuts = 2 10 | integer, parameter :: shellfish = 3 11 | integer, parameter :: strawberries = 4 12 | integer, parameter :: tomatoes = 5 13 | integer, parameter :: chocolate = 6 14 | integer, parameter :: pollen = 7 15 | integer, parameter :: cats = 8 16 | 17 | integer, dimension(ALLERGY_TYPES_LEN), parameter :: ALLERGY_TYPES_BITS = (/ & 18 | & 1, 2, 4, 8, 16, 32, 64, 128 /) 19 | 20 | character(len=12), dimension(ALLERGY_TYPES_LEN), parameter :: ALLERGY_TYPES_STR = (/ & 21 | & "eggs ", & 22 | & "peanuts ", & 23 | & "shellfish ", & 24 | & "strawberries", & 25 | & "tomatoes ", & 26 | & "chocolate ", & 27 | & "pollen ", & 28 | & "cats " /) 29 | 30 | contains 31 | 32 | logical function allergicTo(allergy_str, allergy_key) 33 | character(len=*), intent(in) :: allergy_str 34 | integer, intent(in) :: allergy_key 35 | integer allergy_idx 36 | 37 | allergy_idx = get_allergy_idx_from_str(allergy_str) 38 | allergicTo = btest(allergy_key,allergy_idx-1 ) 39 | end function 40 | 41 | 42 | function allergicList(allergy_key) 43 | integer, intent(in) :: allergy_key 44 | character(len=100) :: allergicList 45 | integer i 46 | 47 | allergicList = ' ' 48 | 49 | do i=1,ALLERGY_TYPES_LEN 50 | if ( btest(allergy_key,i-1 ) ) then 51 | allergicList = trim(allergicList)//' '//trim(ALLERGY_TYPES_STR(i)) 52 | end if 53 | end do 54 | allergicList = adjustl(allergicList) 55 | end function 56 | 57 | 58 | integer function get_allergy_idx_from_str(allergy_str) 59 | character(len=*), intent(in) :: allergy_str 60 | integer :: i 61 | 62 | get_allergy_idx_from_str = unknown 63 | 64 | do i=1,ALLERGY_TYPES_LEN 65 | if ( trim(allergy_str) == trim(ALLERGY_TYPES_STR(i) )) then 66 | get_allergy_idx_from_str = i 67 | end if 68 | end do 69 | if (get_allergy_idx_from_str == unknown) then 70 | write(*,*) 'ERROR: Wrong allergy type' 71 | end if 72 | end function 73 | 74 | end module 75 | -------------------------------------------------------------------------------- /exercises/practice/binary-search/binary_search_test.f90: -------------------------------------------------------------------------------- 1 | program binary_search_test_main 2 | use TesterMain 3 | use binary_search 4 | implicit none 5 | 6 | ! Test 1: finds a value in an array with one element 7 | call assert_equal(1, find([6], 6), "finds a value in an array with one element") 8 | 9 | ! Test 2: finds a value in the middle of an array 10 | call assert_equal(4, find([1, 3, 4, 6, 8, 9, 11], 6), "finds a value in the middle of an array") 11 | 12 | ! Test 3: finds a value at the beginning of an array 13 | call assert_equal(1, find([1, 3, 4, 6, 8, 9, 11], 1), "finds a value at the beginning of an array") 14 | 15 | ! Test 4: finds a value at the end of an array 16 | call assert_equal(7, find([1, 3, 4, 6, 8, 9, 11], 11), "finds a value at the end of an array") 17 | 18 | ! Test 5: finds a value in an array of odd length 19 | call assert_equal(10, find([1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634], 144), "finds a value in an array of odd length") 20 | 21 | ! Test 6: finds a value in an array of even length 22 | call assert_equal(6, find([1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377], 21), "finds a value in an array of even length") 23 | 24 | ! Test 7: identifies that a value is not included in the array 25 | ! ERROR: value not in array 26 | call assert_equal(-1, find([1, 3, 4, 6, 8, 9, 11], 7), "identifies that a value is not included in the array") 27 | 28 | ! Test 8: a value smaller than the array's smallest value is not found 29 | ! ERROR: value not in array 30 | call assert_equal(-1, find([1, 3, 4, 6, 8, 9, 11], 0), "a value smaller than the array's smallest value is not found") 31 | 32 | ! Test 9: a value larger than the array's largest value is not found 33 | ! ERROR: value not in array 34 | call assert_equal(-1, find([1, 3, 4, 6, 8, 9, 11], 13), "a value larger than the array's largest value is not found") 35 | 36 | ! Test 10: nothing is found in an empty array 37 | ! ERROR: value not in array 38 | call assert_equal(-1, find([integer ::], 1), "nothing is found in an empty array") 39 | 40 | ! Test 11: nothing is found when the left and right bounds cross 41 | ! ERROR: value not in array 42 | call assert_equal(-1, find([1, 2], 0), "nothing is found when the left and right bounds cross") 43 | 44 | call test_report() 45 | 46 | end program 47 | 48 | -------------------------------------------------------------------------------- /bin/add-exercise: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | if [ $# -ne 1 ]; then 6 | echo "Usage: bin/add-exercise " 7 | exit 1 8 | fi 9 | 10 | command -v jq >/dev/null 2>&1 || { 11 | echo >&2 "jq is required but not installed. Please install it and make sure it's in your PATH." 12 | exit 1 13 | } 14 | command -v curl >/dev/null 2>&1 || { 15 | echo >&2 "curl is required but not installed. Please install it and make sure it's in your PATH." 16 | exit 1 17 | } 18 | python3 -c 'import toml' 2>/dev/null || { 19 | echo >&2 "The python3 toml module is required: pip3 install toml" 20 | exit 1 21 | } 22 | 23 | bin/fetch-configlet 24 | 25 | # Add entry for exercise in config.json 26 | slug="${1}" 27 | name=$(echo "${slug}" | sed 's/\b\w/\u&/g') 28 | uuid=$(bin/configlet uuid) 29 | jq --arg slug "${slug}" --arg uuid "${uuid}" --arg name "${name}" \ 30 | '.exercises.practice += [{slug: $slug, name: $name, uuid: $uuid, practices: [], prerequisites: [], difficulty: 1}]' \ 31 | config.json > config.json.tmp && mv config.json.tmp config.json 32 | 33 | # Sync the exercise 34 | bin/configlet sync --update --yes --tests include --filepaths --metadata --docs --exercise "${slug}" 35 | 36 | 37 | if [ -n "${XDG_CACHE_HOME}" ] && [ -d "${XDG_CACHE_HOME}" ]; then 38 | os_cache_dir="${XDG_CACHE_HOME}" 39 | elif [ "$(uname)" == "Darwin" ]; then 40 | os_cache_dir="${HOME}/Library/Caches" 41 | else 42 | os_cache_dir="${HOME}/.cache" 43 | fi 44 | 45 | cache_dir="${os_cache_dir}/exercism/configlet/problem-specifications" 46 | 47 | snake_name=$(echo "${slug}" | sed 's/-/_/g') 48 | exercise_dir="exercises/practice/${slug}" 49 | stub_file_path="${exercise_dir}/${snake_name}.f90" 50 | test_file_path="${exercise_dir}/${snake_name}_test.f90" 51 | example_file_path="${exercise_dir}/.meta/example.f90" 52 | canonical_data_file_path="${cache_dir}/exercises/${slug}/canonical-data.json" 53 | cmakelists_file_path="${exercise_dir}/CMakeLists.txt" 54 | 55 | touch "${stub_file_path}" 56 | touch "${test_file_path}" 57 | touch "${example_file_path}" 58 | 59 | cp config/CMakeLists.txt "${cmakelists_file_path}" 60 | 61 | # Update the new exercise files, which includes generating the tests 62 | python3 bin/update-new-exercise-files.py "${slug}" "${snake_name}" "${stub_file_path}" "${test_file_path}" "${example_file_path}" "${canonical_data_file_path}" 63 | -------------------------------------------------------------------------------- /exercises/practice/isbn-verifier/.meta/tests.toml: -------------------------------------------------------------------------------- 1 | # This is an auto-generated file. 2 | # 3 | # Regenerating this file via `configlet sync` will: 4 | # - Recreate every `description` key/value pair 5 | # - Recreate every `reimplements` key/value pair, where they exist in problem-specifications 6 | # - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) 7 | # - Preserve any other key/value pair 8 | # 9 | # As user-added comments (using the # character) will be removed when this file 10 | # is regenerated, comments can be added via a `comment` key. 11 | 12 | [0caa3eac-d2e3-4c29-8df8-b188bc8c9292] 13 | description = "valid isbn" 14 | 15 | [19f76b53-7c24-45f8-87b8-4604d0ccd248] 16 | description = "invalid isbn check digit" 17 | 18 | [4164bfee-fb0a-4a1c-9f70-64c6a1903dcd] 19 | description = "valid isbn with a check digit of 10" 20 | 21 | [3ed50db1-8982-4423-a993-93174a20825c] 22 | description = "check digit is a character other than X" 23 | 24 | [9416f4a5-fe01-4b61-a07b-eb75892ef562] 25 | description = "invalid check digit in isbn is not treated as zero" 26 | 27 | [c19ba0c4-014f-4dc3-a63f-ff9aefc9b5ec] 28 | description = "invalid character in isbn is not treated as zero" 29 | 30 | [28025280-2c39-4092-9719-f3234b89c627] 31 | description = "X is only valid as a check digit" 32 | 33 | [f6294e61-7e79-46b3-977b-f48789a4945b] 34 | description = "valid isbn without separating dashes" 35 | 36 | [185ab99b-3a1b-45f3-aeec-b80d80b07f0b] 37 | description = "isbn without separating dashes and X as check digit" 38 | 39 | [7725a837-ec8e-4528-a92a-d981dd8cf3e2] 40 | description = "isbn without check digit and dashes" 41 | 42 | [47e4dfba-9c20-46ed-9958-4d3190630bdf] 43 | description = "too long isbn and no dashes" 44 | 45 | [737f4e91-cbba-4175-95bf-ae630b41fb60] 46 | description = "too short isbn" 47 | 48 | [5458a128-a9b6-4ff8-8afb-674e74567cef] 49 | description = "isbn without check digit" 50 | 51 | [70b6ad83-d0a2-4ca7-a4d5-a9ab731800f7] 52 | description = "check digit of X should not be used for 0" 53 | 54 | [94610459-55ab-4c35-9b93-ff6ea1a8e562] 55 | description = "empty isbn" 56 | 57 | [7bff28d4-d770-48cc-80d6-b20b3a0fb46c] 58 | description = "input is 9 characters" 59 | 60 | [ed6e8d1b-382c-4081-8326-8b772c581fec] 61 | description = "invalid characters are not ignored after checking length" 62 | 63 | [daad3e58-ce00-4395-8a8e-e3eded1cdc86] 64 | description = "invalid characters are not ignored before checking length" 65 | 66 | [fb5e48d8-7c03-4bfb-a088-b101df16fdc3] 67 | description = "input is too long but contains a valid isbn" 68 | -------------------------------------------------------------------------------- /exercises/practice/rational-numbers/.meta/example.f90: -------------------------------------------------------------------------------- 1 | 2 | module rational_numbers 3 | implicit none 4 | contains 5 | 6 | function add(r1,r2) 7 | integer,dimension(2) :: add, r1,r2 8 | !(a1 * b2 + a2 * b1) / (b1 * b2) 9 | add(1) = r1(1)*r2(2)+r2(1)*r1(2) 10 | add(2) = r1(2)*r2(2) 11 | add = reduce(add) 12 | end function 13 | 14 | function sub(r1,r2) 15 | integer,dimension(2) :: sub, r1,r2 16 | !r₁ - r₂ = a₁/b₁ - a₂/b₂ = (a₁ * b₂ - a₂ * b₁) / (b₁ * b₂). 17 | sub(1) = r1(1)*r2(2)-r2(1)*r1(2) 18 | sub(2) = r1(2)*r2(2) 19 | sub = reduce(sub) 20 | end function 21 | 22 | function mul(r1,r2) 23 | integer,dimension(2) :: mul, r1,r2 24 | !r₁ * r₂ = (a₁ * a₂) / (b₁ * b₂). 25 | mul(1) = r1(1)*r2(1) 26 | mul(2) = r1(2)*r2(2) 27 | mul = reduce(mul) 28 | end function 29 | 30 | function div(r1,r2) 31 | integer,dimension(2) :: div, r1,r2 32 | ! r₁ / r₂ = (a₁ * b₂) / (a₂ * b₁) 33 | div(1) = r1(1)*r2(2) 34 | div(2) = r1(2)*r2(1) 35 | div = reduce(div) 36 | end function 37 | 38 | function rational_abs(r1) 39 | integer,dimension(2) :: rational_abs, r1 40 | rational_abs(1) = abs(r1(1)) 41 | rational_abs(2) = abs(r1(2)) 42 | end function 43 | 44 | 45 | function rational_to_pow(r1, ex) 46 | integer,dimension(2) :: rational_to_pow, r1 47 | integer :: ex 48 | !(a1 * b2 + a2 * b1) / (b1 * b2) 49 | rational_to_pow(1) = r1(1)**ex 50 | rational_to_pow(2) = r1(2)**ex 51 | end function 52 | 53 | 54 | function real_to_rational_pow(ex,r1) 55 | integer,dimension(2) :: r1 56 | real :: real_to_rational_pow,ex 57 | !(a1 * b2 + a2 * b1) / (b1 * b2) 58 | if ( r1(1)==0 ) then 59 | real_to_rational_pow=1.0 60 | else 61 | real_to_rational_pow = ex**(real(r1(1))/real(r1(2))) 62 | endif 63 | end function 64 | 65 | 66 | function gcd(m,n) 67 | integer,intent(in) :: m, n 68 | integer :: gcd,irest,ifirst 69 | ifirst=abs(m) 70 | gcd=abs(n) 71 | if(gcd==0)then 72 | gcd=ifirst 73 | else 74 | do 75 | irest = mod(ifirst,gcd) 76 | if(irest == 0) exit 77 | ifirst = gcd 78 | gcd = irest 79 | enddo 80 | gcd= abs(gcd) 81 | endif 82 | end function 83 | 84 | function reduce(r1) 85 | integer,dimension(2) :: reduce, r1 86 | integer :: gcd_num 87 | !(a1 * b2 + a2 * b1) / (b1 * b2) 88 | gcd_num = gcd(r1(1),r1(2)) 89 | reduce(:) = r1(:)/gcd_num 90 | if (reduce(2)<0)then ! fix sign 91 | reduce = -reduce 92 | endif 93 | end function 94 | 95 | end module 96 | --------------------------------------------------------------------------------