diff --git a/config.json b/config.json index 4489ec1..f15480d 100644 --- a/config.json +++ b/config.json @@ -124,6 +124,14 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "collatz-conjecture", + "name": "Collatz Conjecture", + "uuid": "dd18fd4d-21de-40f8-9d92-2c5a1d1e7133", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "difference-of-squares", "name": "Difference of Squares", diff --git a/config.yaml b/config.yaml index 462a6a9..e1f69fa 100644 --- a/config.yaml +++ b/config.yaml @@ -121,6 +121,13 @@ exercises: prerequisites: [] difficulty: 2 + - slug: collatz-conjecture + name: Collatz Conjecture + uuid: dd18fd4d-21de-40f8-9d92-2c5a1d1e7133 + practices: [] + prerequisites: [] + difficulty: 2 + - slug: difference-of-squares name: Difference of Squares uuid: de0c68d4-f0c3-4bb7-9ab2-378f9034bc82 diff --git a/exercises/practice/collatz-conjecture/.docs/instructions.md b/exercises/practice/collatz-conjecture/.docs/instructions.md new file mode 100644 index 0000000..ba06048 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +The Collatz Conjecture or 3x+1 problem can be summarized as follows: + +Take any positive integer n. +If n is even, divide n by 2 to get n / 2. +If n is odd, multiply n by 3 and add 1 to get 3n + 1. +Repeat the process indefinitely. +The conjecture states that no matter which number you start with, you will always reach 1 eventually. + +Given a number n, return the number of steps required to reach 1. + +## Examples + +Starting with n = 12, the steps would be as follows: + +0. 12 +1. 6 +2. 3 +3. 10 +4. 5 +5. 16 +6. 8 +7. 4 +8. 2 +9. 1 + +Resulting in 9 steps. +So for input n = 12, the return value would be 9. diff --git a/exercises/practice/collatz-conjecture/.meta/.yamlscript/exercise.mk b/exercises/practice/collatz-conjecture/.meta/.yamlscript/exercise.mk new file mode 100644 index 0000000..2506034 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/.yamlscript/exercise.mk @@ -0,0 +1 @@ +YS_VERSION := 0.1.75 diff --git a/exercises/practice/collatz-conjecture/.meta/Makefile b/exercises/practice/collatz-conjecture/.meta/Makefile new file mode 100644 index 0000000..ba39335 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/Makefile @@ -0,0 +1,28 @@ +SHELL := bash + +BASE := $(shell pwd) + +export YS_VERSION := 0.1.76 + +YS_LOCAL_PREFIX := ../../../../.local/v$(YS_VERSION) + +YS_LOCAL_BIN := $(YS_LOCAL_PREFIX)/bin + +YS_BIN := $(YS_LOCAL_BIN)/ys-$(YS_VERSION) + +TEST_FILE ?= $(wildcard *-test.ys) + + +export PATH := $(YS_LOCAL_BIN):$(PATH) + +export YSPATH := $(BASE) + + +default: + +test: $(YS_BIN) + prove -v $(TEST_FILE) + +$(YS_BIN): + curl -s https://yamlscript.org/install | \ + BIN=1 VERSION=$(YS_VERSION) PREFIX=$(YS_LOCAL_PREFIX) bash >/dev/null diff --git a/exercises/practice/collatz-conjecture/.meta/collatz-conjecture-test.ys b/exercises/practice/collatz-conjecture/.meta/collatz-conjecture-test.ys new file mode 100644 index 0000000..ad3c893 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/collatz-conjecture-test.ys @@ -0,0 +1,40 @@ +#!/usr/bin/env ys-0 + +require ys::taptest: :all + +use: collatz-conjecture + +test:: +- name: Zero steps for one + code: steps(1) + want: 0 + uuid: 540a3d51-e7a6-47a5-92a3-4ad1838f0bfd + +- name: Divide if even + code: steps(16) + want: 4 + uuid: 3d76a0a6-ea84-444a-821a-f7857c2c1859 + +- name: Even and odd steps + code: steps(12) + want: 9 + uuid: 754dea81-123c-429e-b8bc-db20b05a87b9 + +- name: Large number of even and odd steps + code: steps(1000000) + want: 152 + uuid: ecfd0210-6f85-44f6-8280-f65534892ff6 + +- name: Zero is an error + code: steps(0) + what: error + want: Only positive integers are allowed + uuid: 2187673d-77d6-4543-975e-66df6c50e2da + +- name: Negative value is an error + code: steps(-15) + what: error + want: Only positive integers are allowed + uuid: ec11f479-56bc-47fd-a434-bcd7a31a7a2e + +done: 6 diff --git a/exercises/practice/collatz-conjecture/.meta/collatz-conjecture.ys b/exercises/practice/collatz-conjecture/.meta/collatz-conjecture.ys new file mode 100644 index 0000000..5fa4d8a --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/collatz-conjecture.ys @@ -0,0 +1,11 @@ +!yamlscript/v0 + +defn steps(number): + when-not pos?(number): + die('Only positive integers are allowed') + + loop num number, steps 0: + cond: + num == 1: steps + even?(num): recur((num / 2), steps.++) + else: recur((num * 3).++, steps.++) diff --git a/exercises/practice/collatz-conjecture/.meta/config.json b/exercises/practice/collatz-conjecture/.meta/config.json new file mode 100644 index 0000000..8963e14 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/config.json @@ -0,0 +1,23 @@ +{ + "authors": [ + "ingydotnet" + ], + "files": { + "solution": [ + "collatz-conjecture.ys" + ], + "test": [ + "collatz-conjecture-test.ys", + "GNUmakefile", + "Makefile", + ".yamlscript/exercise.mk", + ".yamlscript/exercism-ys-installer" + ], + "example": [ + ".meta/collatz-conjecture.ys" + ] + }, + "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.", + "source": "An unsolved problem in mathematics named after mathematician Lothar Collatz", + "source_url": "https://en.wikipedia.org/wiki/3x_%2B_1_problem" +} diff --git a/exercises/practice/collatz-conjecture/.meta/tests.toml b/exercises/practice/collatz-conjecture/.meta/tests.toml new file mode 100644 index 0000000..cc34e16 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.meta/tests.toml @@ -0,0 +1,38 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[540a3d51-e7a6-47a5-92a3-4ad1838f0bfd] +description = "zero steps for one" + +[3d76a0a6-ea84-444a-821a-f7857c2c1859] +description = "divide if even" + +[754dea81-123c-429e-b8bc-db20b05a87b9] +description = "even and odd steps" + +[ecfd0210-6f85-44f6-8280-f65534892ff6] +description = "large number of even and odd steps" + +[7d4750e6-def9-4b86-aec7-9f7eb44f95a3] +description = "zero is an error" +include = false + +[2187673d-77d6-4543-975e-66df6c50e2da] +description = "zero is an error" +reimplements = "7d4750e6-def9-4b86-aec7-9f7eb44f95a3" + +[c6c795bf-a288-45e9-86a1-841359ad426d] +description = "negative value is an error" +include = false + +[ec11f479-56bc-47fd-a434-bcd7a31a7a2e] +description = "negative value is an error" +reimplements = "c6c795bf-a288-45e9-86a1-841359ad426d" diff --git a/exercises/practice/collatz-conjecture/.yamlscript/exercise.mk b/exercises/practice/collatz-conjecture/.yamlscript/exercise.mk new file mode 100644 index 0000000..2506034 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.yamlscript/exercise.mk @@ -0,0 +1 @@ +YS_VERSION := 0.1.75 diff --git a/exercises/practice/collatz-conjecture/.yamlscript/exercism-ys-installer b/exercises/practice/collatz-conjecture/.yamlscript/exercism-ys-installer new file mode 100644 index 0000000..ae3fa01 --- /dev/null +++ b/exercises/practice/collatz-conjecture/.yamlscript/exercism-ys-installer @@ -0,0 +1,127 @@ +#!/env/bin/env bash + +set -euo pipefail + +intro-prompt() ( + cat <<... +-------------------------------------------------------------------------------- + +This YAMLScript Exercism exercise requires the YAMLScript version $version +interpreter command file to be installed here: + + $prefix/bin/ys + +You can install it by pressing Enter now, or by running this command: + + $make install-ys + +This should only take a few seconds and you only need to do this once. +Other exercises will use the same file. + +See https://yamlscript.org/doc/install/ for more YAMLScript installation info. + +-------------------------------------------------------------------------------- + +Would you like to install the 'ys' file now? + +... + + printf "Press Enter to install. Ctl-C to Quit."; read -r +) + +main() { + setup "$@" + + install-from-local + + $auto && intro-prompt + + installed || install-from-release || true + installed || install-from-build || true + installed || + die "Installing '$installed' failed. Giving up." \ + "Consider filing an issue at: $gh_issue_url" + + echo + echo 'Success!' + echo "$installed is now installed." + echo +} + +installed() { + [[ -f $installed ]] +} + +install-from-local() { + local path + path=$(command -v "$ysfq") || true + if [[ -f $path ]]; then + mkdir -p "$bin" + cp "$path" "$bin"/ + ln -fs "$ysfq" "$bin/ys-0" + ln -fs "$ysfq" "$bin/ys" + (installed && $auto) && exit + true + fi +} + +install-from-release() ( + set -x + curl -s https://yamlscript.org/install | + BIN=1 VERSION="$version" PREFIX="$prefix" bash +) + +install-from-build() ( + cat <<... + +The binary release installation failed. +We can attempt to build and install $ysfq now. +This can take from 1 to 5 minutes to complete. + +... + + printf "Press Enter to install. Ctl-C to Quit."; read -r + + [[ -d /tmp && -w /tmp ]] || + die "Can't write to /tmp" \ + 'Giving up.' + + set -x + + rm -fr "$yamlscript_clone" + + git clone --branch="$version" "$yamlscript_repo" "$yamlscript_clone" + + "$make" -C "$yamlscript_clone/ys" install PREFIX="$prefix" +) + +setup() { + version=$1 + prefix=$2 + make=$3 + auto=false + [[ ${4-} ]] && auto=true + + [[ $version =~ ^0\.1\.[0-9]+$ ]] || + die "Invalid YS_VERSION '$version'" + + bin=$prefix/bin + ysfq=ys-$version + installed=$bin/$ysfq + + if installed; then + echo "'$installed' is already installed." + exit + fi + + yamlscript_repo=https://github.com/yaml/yamlscript + yamlscript_clone=/tmp/yamlscript-exercism + gh_issue_url=https://github.com/exercism/yamlscript/issues +} + +die() { + printf '%s\n' "$@" >&2 + exit 1 +} + +main "$@" diff --git a/exercises/practice/collatz-conjecture/GNUmakefile b/exercises/practice/collatz-conjecture/GNUmakefile new file mode 100644 index 0000000..381cd29 --- /dev/null +++ b/exercises/practice/collatz-conjecture/GNUmakefile @@ -0,0 +1,49 @@ +SHELL := bash + +BASE := $(shell pwd) + +export YS_VERSION := 0.1.76 + +YS_LOCAL_PREFIX := ../../../.local/v$(YS_VERSION) +ifeq (,$(shell [[ -d "$(YS_LOCAL_PREFIX)" ]] && echo ok)) +YS_LOCAL_PREFIX := $(shell cd .. && pwd -P)/.local/v$(YS_VERSION) +endif + +YS_LOCAL_BIN := $(YS_LOCAL_PREFIX)/bin +YS_BIN := $(YS_LOCAL_BIN)/ys-$(YS_VERSION) + +YS_INSTALLER := .yamlscript/exercism-ys-installer +YS_INSTALLER_CMD := \ + bash $(YS_INSTALLER) $(YS_VERSION) $(YS_LOCAL_PREFIX) $(MAKE) + +TEST_FILE ?= $(wildcard *-test.ys) + +export PATH := $(YS_LOCAL_BIN):$(PATH) +export YSPATH := $(BASE) + + +#------------------------------------------------------------------------------- +default: + @echo " No default make rule. Try 'make test'." + +test: $(YS_BIN) + prove -v $(TEST_FILE) + +install-ys: + @$(YS_INSTALLER_CMD) + +uninstall-ys: + rm -fr $(YS_LOCAL_PREFIX) + + +#------------------------------------------------------------------------------- +ifdef EXERCISM_YAMLSCRIPT_GHA +$(YS_BIN): + +else ifeq (/mnt/,$(dir $(BASE))) +$(YS_BIN): + +else +$(YS_BIN): + @$(YS_INSTALLER_CMD) auto +endif diff --git a/exercises/practice/collatz-conjecture/Makefile b/exercises/practice/collatz-conjecture/Makefile new file mode 100644 index 0000000..06b6f00 --- /dev/null +++ b/exercises/practice/collatz-conjecture/Makefile @@ -0,0 +1,8 @@ +# This Makefile is a decoy to attempt to detect when a non-GNU make is being +# used and alert the user. + +test: + @echo "You appear to be using a non-GNU version of the 'make' program." + @echo "The YAMLScript Exercism track requires you to use GNU make." + @echo "Please try 'make $@' again using GNU make." + @exit 1 diff --git a/exercises/practice/collatz-conjecture/collatz-conjecture-test.ys b/exercises/practice/collatz-conjecture/collatz-conjecture-test.ys new file mode 100644 index 0000000..3145505 --- /dev/null +++ b/exercises/practice/collatz-conjecture/collatz-conjecture-test.ys @@ -0,0 +1,44 @@ +#!/usr/bin/env ys-0 + +require ys::taptest: :all + +use: collatz-conjecture + +test:: +- name: Zero steps for one + code: steps(1) + want: 0 + +- name: Divide if even + code: steps(16) + want: 4 + +- name: Even and odd steps + code: steps(12) + want: 9 + +- name: Large number of even and odd steps + code: steps(1000000) + want: 152 + +- name: Zero is an error + code: steps(0) + what: error + want: Only positive numbers are allowed + +- name: Zero is an error + code: steps(0) + what: error + want: Only positive integers are allowed + +- name: Negative value is an error + code: steps(-15) + what: error + want: Only positive numbers are allowed + +- name: Negative value is an error + code: steps(-15) + what: error + want: Only positive integers are allowed + +done: 8 diff --git a/exercises/practice/collatz-conjecture/collatz-conjecture.ys b/exercises/practice/collatz-conjecture/collatz-conjecture.ys new file mode 100644 index 0000000..e91840b --- /dev/null +++ b/exercises/practice/collatz-conjecture/collatz-conjecture.ys @@ -0,0 +1,4 @@ +!yamlscript/v0 + +defn steps(number): + # Implement the 'steps' function.