Skip to content

Add intergalactic transmission #2969

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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).
Original file line number Diff line number Diff line change
@@ -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.
19 changes: 19 additions & 0 deletions exercises/practice/intergalactic-transmission/.meta/config.json
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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<Integer> getTransmitSequence(List<Integer> message) {
List<Integer> 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<Integer> decodeSequence(List<Integer> receivedSeq) {
if (receivedSeq.isEmpty()) {
return new ArrayList<>();
}

List<Integer> 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);
}
}
88 changes: 88 additions & 0 deletions exercises/practice/intergalactic-transmission/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -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"
25 changes: 25 additions & 0 deletions exercises/practice/intergalactic-transmission/build.gradle
Original file line number Diff line number Diff line change
@@ -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"]
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -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
Loading