diff --git a/config.json b/config.json index 1356cbf81..642132dee 100644 --- a/config.json +++ b/config.json @@ -1442,6 +1442,14 @@ ], "difficulty": 6 }, + { + "slug": "intergalactic-transmission", + "name": "Intergalactic Transmission", + "uuid": "b1c6dfc2-414b-45b2-9277-8b9f8bb3bcf3", + "practices": [], + "prerequisites": [], + "difficulty": 6 + }, { "slug": "anagram", "name": "Anagram", diff --git a/exercises/practice/intergalactic-transmission/.docs/instructions.append.md b/exercises/practice/intergalactic-transmission/.docs/instructions.append.md new file mode 100644 index 000000000..a5f1cad0d --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.docs/instructions.append.md @@ -0,0 +1,3 @@ +# Instructions append + +Although we're dealing with bytes of data, the inputs and outputs are `List` (instead of `byte[]`) to avoid the need to cast or convert negative values for bytes 128 to 255. diff --git a/exercises/practice/intergalactic-transmission/.docs/instructions.md b/exercises/practice/intergalactic-transmission/.docs/instructions.md new file mode 100644 index 000000000..549708817 --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.docs/instructions.md @@ -0,0 +1,54 @@ +# Instructions + +Your job is to help implement + +- the transmitter, which calculates the transmission sequence, and +- the receiver, which decodes it. + +A parity bit is simple way of detecting transmission errors. +The transmitters and receivers can only transmit and receive _exactly_ eight bits at a time (including the parity bit). +The parity bit is set so that there is an _even_ number of 1 bits in each transmission, and the parity bit is always the first bit from the right. +So if the receiver receives `11000001`, `01110101` or `01000000` (i.e. a transmission with an odd number of 1 bits), it knows there is an error. + +However, messages are rarely this short, and need to be transmitted in a sequence when they are longer. + +For example, consider the message `11000000 00000001 11000000 11011110` (or `C0 01 C0 DE` in hex). + +Since each transmission contains exactly eight bits, it can only contain seven bits of data and the parity bit. +A parity bit must then be inserted after every seven bits of data: + +```text +11000000 00000001 11000000 11011110 + ↑ ↑ ↑ ↑ (7th bits) +``` + +The transmission sequence for this message looks like this: + +```text +1100000_ 0000000_ 0111000_ 0001101_ 1110 + ↑ ↑ ↑ ↑ (parity bits) +``` + +The data in the first transmission in the sequence (`1100000`) has two 1 bits (an even number), so the parity bit is 0. +The first transmission becomes `11000000` (or `C0` in hex). + +The data in the next transmission (`0000000`) has zero 1 bits (an even number again), so the parity bit is 0 again. +The second transmission thus becomes `00000000` (or `00` in hex). + +The data for the next two transmissions (`0111000` and `0001101`) have three 1 bits. +Their parity bits are set to 1 so that they have an even number of 1 bits in the transmission. +They are transmitted as `01110001` and `00011011` (or `71` and `1B` in hex). + +The last transmission (`1110`) has only four bits of data. +Since exactly eight bits are transmitted at a time and the parity bit is the rightmost bit, three 0 bits and then the parity bit are added to make up eight bits. +It now looks like this (where `_` is the parity bit): + +```text +1110 000_ + ↑↑↑ (added 0 bits) +``` + +There is an odd number of 1 bits again, so the parity bit is 1. +The last transmission in the sequence becomes `11100001` (or `E1` in hex). + +The entire transmission sequence for this message is `11000000 00000000 01110001 00011011 11100001` (or `C0 00 71 1B E1` in hex). diff --git a/exercises/practice/intergalactic-transmission/.docs/introduction.md b/exercises/practice/intergalactic-transmission/.docs/introduction.md new file mode 100644 index 000000000..f19dffbea --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.docs/introduction.md @@ -0,0 +1,23 @@ +# Introduction + +Trillions upon trillions of messages zip between Earth and neighboring galaxies every millisecond. +But transmitting over such long distances is tricky. +Pesky solar flares, temporal distortions, stray forces, and even the flap of a space butterfly's wing can cause a random bit to change during transmission. + +Now imagine the consequences: + +- Crashing the Intergalactic Share Market when "buy low" turns to "sell now". +- Losing contact with the Kepler Whirl system when "save new worm hole" becomes "cave new worm hole". +- Or plunging the universe into existential horror by replacing a cowboy emoji 🤠 with a clown emoji 🤡. + +Detecting corrupted messages isn't just important — it's critical. +The receiver _must_ know when something has gone wrong before disaster strikes. + +But how? +Scientists and engineers from across the universe have been battling this problem for eons. +Entire cosmic AI superclusters churn through the data. +And then, one day, a legend resurfaces — an ancient, powerful method, whispered in debugging forums, muttered by engineers who've seen too much... + +The Parity Bit! + +A method so simple, so powerful, that it might just save interstellar communication. diff --git a/exercises/practice/intergalactic-transmission/.meta/config.json b/exercises/practice/intergalactic-transmission/.meta/config.json new file mode 100644 index 000000000..6d97d1430 --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "jagdish-15" + ], + "files": { + "solution": [ + "src/main/java/IntergalacticTransmission.java" + ], + "test": [ + "src/test/java/IntergalacticTransmissionTest.java" + ], + "example": [ + ".meta/src/reference/java/IntergalacticTransmission.java" + ] + }, + "blurb": "Add parity bits to a message for transmission", + "source": "Kah Goh", + "source_url": "https://github.com/exercism/problem-specifications/pull/2543" +} diff --git a/exercises/practice/intergalactic-transmission/.meta/src/reference/java/IntergalacticTransmission.java b/exercises/practice/intergalactic-transmission/.meta/src/reference/java/IntergalacticTransmission.java new file mode 100644 index 000000000..d27721e1d --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.meta/src/reference/java/IntergalacticTransmission.java @@ -0,0 +1,82 @@ +import java.util.ArrayList; +import java.util.List; + +public class IntergalacticTransmission { + + private static final byte INIT_UPPER_MASK = (byte) 0xFE; + + public static List getTransmitSequence(List message) { + List transmitSeq = new ArrayList<>(); + byte carry = 0; + byte upperMask = INIT_UPPER_MASK; + + for (int i = 0; i < message.size(); i++) { + byte currentByte = message.get(i).byteValue(); + + if (upperMask == 0) { + transmitSeq.add((int) addParity(carry) & 0xFF); + carry = 0; + upperMask = (byte) 0xFE; + } + + int shiftPlaces = Integer.numberOfTrailingZeros(upperMask & 0xFF); + int current = ((carry & 0xFF) << (8 - shiftPlaces)) | ((currentByte & 0xFF) >>> shiftPlaces); + transmitSeq.add((int) addParity((byte) current) & 0xFF); + + carry = (byte) (currentByte & ~upperMask); + upperMask = (byte) (upperMask << 1); + } + + if (upperMask != INIT_UPPER_MASK) { + byte lastGroup = (byte) ((carry & 0xFF) << Integer.bitCount(upperMask & 0xFF)); + transmitSeq.add((int) addParity(lastGroup) & 0xFF); + } + + return transmitSeq; + } + + private static byte addParity(byte source) { + if (Integer.bitCount(source & 0x7F) % 2 == 0) { + return (byte) (source << 1); + } else { + return (byte) ((source << 1) | 1); + } + } + + public static List decodeSequence(List receivedSeq) { + if (receivedSeq.isEmpty()) { + return new ArrayList<>(); + } + + List decodedMessage = new ArrayList<>(); + byte byteToAdd = 0x00; + byte upperMask = (byte) 0xFF; + + for (int i = 0; i < receivedSeq.size(); i++) { + byte currentByte = receivedSeq.get(i).byteValue(); + + if (upperMask == (byte) 0xFF) { + byteToAdd = getByteData(currentByte); + upperMask = (byte) 0x80; + continue; + } + + byte currentByteData = getByteData(currentByte); + int shiftPlaces = Integer.numberOfTrailingZeros(upperMask & 0xFF); + byte contribution = (byte) ((currentByteData & 0xFF) >>> shiftPlaces); + decodedMessage.add((byteToAdd | contribution) & 0xFF); + + byteToAdd = (byte) (((currentByteData & ~(upperMask | 0x01)) & 0xFF) << Integer.bitCount(upperMask & 0xFF)); + upperMask = (byte) (((upperMask & 0xFF) >>> 1) | 0x80); + } + + return decodedMessage; + } + + private static byte getByteData(byte data) { + if (Integer.bitCount(data & 0xFF) % 2 != 0) { + throw new IllegalArgumentException("Byte has incorrect parity"); + } + return (byte) (data & 0xFE); + } +} diff --git a/exercises/practice/intergalactic-transmission/.meta/tests.toml b/exercises/practice/intergalactic-transmission/.meta/tests.toml new file mode 100644 index 000000000..64a8aaced --- /dev/null +++ b/exercises/practice/intergalactic-transmission/.meta/tests.toml @@ -0,0 +1,88 @@ +# 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. + +[f99d4046-b429-4582-9324-f0bcac7ab51c] +description = "calculate transmit sequences -> empty message" + +[ee27ea2d-8999-4f23-9275-8f6879545f86] +description = "calculate transmit sequences -> 0x00 is transmitted as 0x0000" + +[97f27f98-8020-402d-be85-f21ba54a6df0] +description = "calculate transmit sequences -> 0x02 is transmitted as 0x0300" + +[24712fb9-0336-4e2f-835e-d2350f29c420] +description = "calculate transmit sequences -> 0x06 is transmitted as 0x0600" + +[7630b5a9-dba1-4178-b2a0-4a376f7414e0] +description = "calculate transmit sequences -> 0x05 is transmitted as 0x0581" + +[ab4fe80b-ef8e-4a99-b4fb-001937af415d] +description = "calculate transmit sequences -> 0x29 is transmitted as 0x2881" + +[4e200d84-593b-4449-b7c0-4de1b6a0955e] +description = "calculate transmit sequences -> 0xc001c0de is transmitted as 0xc000711be1" + +[fbc537e9-6b21-4f4a-8c2b-9cf9b702a9b7] +description = "calculate transmit sequences -> six byte message" + +[d5b75adf-b5fc-4f77-b4ab-77653e30f07c] +description = "calculate transmit sequences -> seven byte message" + +[6d8b297b-da1d-435e-bcd7-55fbb1400e73] +description = "calculate transmit sequences -> eight byte message" + +[54a0642a-d5aa-490c-be89-8e171a0cab6f] +description = "calculate transmit sequences -> twenty byte message" + +[9a8084dd-3336-474c-90cb-8a852524604d] +description = "decode received messages -> empty message" + +[879af739-0094-4736-9127-bd441b1ddbbf] +description = "decode received messages -> zero message" + +[7a89eeef-96c5-4329-a246-ec181a8e959a] +description = "decode received messages -> 0x0300 is decoded to 0x02" + +[3e515af7-8b62-417f-960c-3454bca7f806] +description = "decode received messages -> 0x0581 is decoded to 0x05" + +[a1b4a3f7-9f05-4b7a-b86e-d7c6fc3f16a9] +description = "decode received messages -> 0x2881 is decoded to 0x29" + +[2e99d617-4c91-4ad5-9217-e4b2447d6e4a] +description = "decode received messages -> first byte has wrong parity" + +[507e212d-3dae-42e8-88b4-2223838ff8d2] +description = "decode received messages -> second byte has wrong parity" + +[b985692e-6338-46c7-8cea-bc38996d4dfd] +description = "decode received messages -> 0xcf4b00 is decoded to 0xce94" + +[7a1f4d48-696d-4679-917c-21b7da3ff3fd] +description = "decode received messages -> 0xe2566500 is decoded to 0xe2ad90" + +[467549dc-a558-443b-80c5-ff3d4eb305d4] +description = "decode received messages -> six byte message" + +[1f3be5fb-093a-4661-9951-c1c4781c71ea] +description = "decode received messages -> seven byte message" + +[6065b8b3-9dcd-45c9-918c-b427cfdb28c1] +description = "decode received messages -> last byte has wrong parity" + +[98af97b7-9cca-4c4c-9de3-f70e227a4cb1] +description = "decode received messages -> eight byte message" + +[aa7d4785-2bb9-43a4-a38a-203325c464fb] +description = "decode received messages -> twenty byte message" + +[4c86e034-b066-42ac-8497-48f9bc1723c1] +description = "decode received messages -> wrong parity on 16th byte" diff --git a/exercises/practice/intergalactic-transmission/build.gradle b/exercises/practice/intergalactic-transmission/build.gradle new file mode 100644 index 000000000..d28f35dee --- /dev/null +++ b/exercises/practice/intergalactic-transmission/build.gradle @@ -0,0 +1,25 @@ +plugins { + id "java" +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation platform("org.junit:junit-bom:5.10.0") + testImplementation "org.junit.jupiter:junit-jupiter" + testImplementation "org.assertj:assertj-core:3.25.1" + + testRuntimeOnly "org.junit.platform:junit-platform-launcher" +} + +test { + useJUnitPlatform() + + testLogging { + exceptionFormat = "full" + showStandardStreams = true + events = ["passed", "failed", "skipped"] + } +} diff --git a/exercises/practice/intergalactic-transmission/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/intergalactic-transmission/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..e6441136f Binary files /dev/null and b/exercises/practice/intergalactic-transmission/gradle/wrapper/gradle-wrapper.jar differ diff --git a/exercises/practice/intergalactic-transmission/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/intergalactic-transmission/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..2deab89d5 --- /dev/null +++ b/exercises/practice/intergalactic-transmission/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/exercises/practice/intergalactic-transmission/gradlew b/exercises/practice/intergalactic-transmission/gradlew new file mode 100644 index 000000000..1aa94a426 --- /dev/null +++ b/exercises/practice/intergalactic-transmission/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/exercises/practice/intergalactic-transmission/gradlew.bat b/exercises/practice/intergalactic-transmission/gradlew.bat new file mode 100644 index 000000000..25da30dbd --- /dev/null +++ b/exercises/practice/intergalactic-transmission/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/exercises/practice/intergalactic-transmission/src/main/java/IntergalacticTransmission.java b/exercises/practice/intergalactic-transmission/src/main/java/IntergalacticTransmission.java new file mode 100644 index 000000000..57541078f --- /dev/null +++ b/exercises/practice/intergalactic-transmission/src/main/java/IntergalacticTransmission.java @@ -0,0 +1,13 @@ +import java.util.List; + +public class IntergalacticTransmission { + + public static List getTransmitSequence(List message) { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + } + + public static List decodeSequence(List sequence) { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + } + +} diff --git a/exercises/practice/intergalactic-transmission/src/test/java/IntergalacticTransmissionTest.java b/exercises/practice/intergalactic-transmission/src/test/java/IntergalacticTransmissionTest.java new file mode 100644 index 000000000..c4ecdef3a --- /dev/null +++ b/exercises/practice/intergalactic-transmission/src/test/java/IntergalacticTransmissionTest.java @@ -0,0 +1,250 @@ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Disabled; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class IntergalacticTransmissionTest { + + @Test + public void calculateTransmitSequencesEmptyMessage() { + List input = List.of(); + List expected = List.of(); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequences0x00IsTransmittedAs0x0000() { + List input = List.of(0x00); + List expected = List.of(0x00, 0x00); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequences0x02IsTransmittedAs0x0300() { + List input = List.of(0x02); + List expected = List.of(0x03, 0x00); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequences0x06IsTransmittedAs0x0600() { + List input = List.of(0x06); + List expected = List.of(0x06, 0x00); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequences0x05IsTransmittedAs0x0581() { + List input = List.of(0x05); + List expected = List.of(0x05, 0x81); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequences0x29IsTransmittedAs0x2881() { + List input = List.of(0x29); + List expected = List.of(0x28, 0x81); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequences0xc001c0deIsTransmittedAs0xc000711be1() { + List input = List.of(0xc0, 0x01, 0xc0, 0xde); + List expected = List.of(0xc0, 0x00, 0x71, 0x1b, 0xe1); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequencesSixByteMessage() { + List input = List.of(0x47, 0x72, 0x65, 0x61, 0x74, 0x21); + List expected = List.of(0x47, 0xb8, 0x99, 0xac, 0x17, 0xa0, 0x84); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequencesSevenByteMessage() { + List input = List.of(0x47, 0x72, 0x65, 0x61, 0x74, 0x31, 0x21); + List expected = List.of(0x47, 0xb8, 0x99, 0xac, 0x17, 0xa0, 0xc5, 0x42); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequencesEightByteMessage() { + List input = List.of(0xc0, 0x01, 0x13, 0x37, 0xc0, 0xde, 0x21, 0x21); + List expected = List.of(0xc0, 0x00, 0x44, 0x66, 0x7d, 0x06, 0x78, 0x42, 0x21, 0x81); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void calculateTransmitSequencesTwentyByteMessage() { + List input = List.of( + 0x45, 0x78, 0x65, 0x72, 0x63, 0x69, 0x73, 0x6d, 0x20, 0x69, + 0x73, 0x20, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x21); + List expected = List.of( + 0x44, 0xbd, 0x18, 0xaf, 0x27, 0x1b, 0xa5, 0xe7, 0x6c, 0x90, + 0x1b, 0x2e, 0x33, 0x03, 0x84, 0xee, 0x65, 0xb8, 0xdb, 0xed, + 0xd7, 0x28, 0x84); + assertThat(IntergalacticTransmission.getTransmitSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeReceivedMessagesEmptyMessage() { + List input = List.of(); + List expected = List.of(); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeReceivedMessagesZeroMessage() { + List input = List.of(0x00, 0x00); + List expected = List.of(0x00); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeReceivedMessages0x0300IsDecodedTo0x02() { + List input = List.of(0x03, 0x00); + List expected = List.of(0x02); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeReceivedMessages0x0581IsDecodedTo0x05() { + List input = List.of(0x05, 0x81); + List expected = List.of(0x05); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeReceivedMessages0x2881IsDecodedTo0x29() { + List input = List.of(0x28, 0x81); + List expected = List.of(0x29); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeFirstByteWrongParity() { + List input = List.of(0x07, 0x00); + assertThrows(IllegalArgumentException.class, () + -> IntergalacticTransmission.decodeSequence(input)); + } + + @Disabled("Remove to run test") + @Test + public void decodeSecondByteWrongParity() { + List input = List.of(0x03, 0x68); + assertThrows(IllegalArgumentException.class, () + -> IntergalacticTransmission.decodeSequence(input)); + } + + @Disabled("Remove to run test") + @Test + public void decode0xcf4b00To0xce94() { + List input = List.of(0xcf, 0x4b, 0x00); + List expected = List.of(0xce, 0x94); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decode0xe2566500To0xe2ad90() { + List input = List.of(0xe2, 0x56, 0x65, 0x00); + List expected = List.of(0xe2, 0xad, 0x90); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeSixByteMessage() { + List input = List.of(0x47, 0xb8, 0x99, 0xac, 0x17, 0xa0, 0x84); + List expected = List.of(0x47, 0x72, 0x65, 0x61, 0x74, 0x21); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeSevenByteMessage() { + List input = List.of(0x47, 0xb8, 0x99, 0xac, 0x17, 0xa0, 0xc5, 0x42); + List expected = List.of(0x47, 0x72, 0x65, 0x61, 0x74, 0x31, 0x21); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeLastByteWrongParity() { + List input = List.of(0x47, 0xb8, 0x99, 0xac, 0x17, 0xa0, 0xc5, 0x43); + assertThrows(IllegalArgumentException.class, () + -> IntergalacticTransmission.decodeSequence(input)); + } + + @Disabled("Remove to run test") + @Test + public void decodeEightByteMessage() { + List input = List.of(0xc0, 0x00, 0x44, 0x66, 0x7d, 0x06, 0x78, 0x42, 0x21, 0x81); + List expected = List.of(0xc0, 0x01, 0x13, 0x37, 0xc0, 0xde, 0x21, 0x21); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeTwentyByteMessage() { + List input = List.of( + 0x44, 0xbd, 0x18, 0xaf, 0x27, 0x1b, 0xa5, 0xe7, 0x6c, 0x90, 0x1b, + 0x2e, 0x33, 0x03, 0x84, 0xee, 0x65, 0xb8, 0xdb, 0xed, 0xd7, 0x28, 0x84); + List expected = List.of( + 0x45, 0x78, 0x65, 0x72, 0x63, 0x69, 0x73, 0x6d, 0x20, 0x69, + 0x73, 0x20, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x21); + assertThat(IntergalacticTransmission.decodeSequence(input)) + .isEqualTo(expected); + } + + @Disabled("Remove to run test") + @Test + public void decodeWrongParityOn16thByte() { + List input = List.of( + 0x44, 0xbd, 0x18, 0xaf, 0x27, 0x1b, 0xa5, 0xe7, 0x6c, 0x90, + 0x1b, 0x2e, 0x33, 0x03, 0x84, 0xef, 0x65, 0xb8, 0xdb, 0xed, 0xd7, 0x28, 0x84); + assertThrows(IllegalArgumentException.class, () + -> IntergalacticTransmission.decodeSequence(input)); + } +} diff --git a/exercises/settings.gradle b/exercises/settings.gradle index 2955a15dc..c46f79877 100644 --- a/exercises/settings.gradle +++ b/exercises/settings.gradle @@ -77,6 +77,7 @@ include 'practice:hangman' include 'practice:hello-world' include 'practice:high-scores' include 'practice:house' +include 'practice:intergalactic-transmission' include 'practice:isbn-verifier' include 'practice:isogram' include 'practice:killer-sudoku-helper'