Skip to content
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

Add intergalactic transmission exercise #2398

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
12 changes: 12 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -2713,6 +2713,18 @@
"for-loops"
],
"difficulty": 7
},
{
"slug": "intergalactic-transmission",
"name": "intergalactic-transmission",
"uuid": "845c8cf4-207c-438f-9d18-c5e7875ee729",
"practices": [
"bit-manipulation"
],
"prerequisites": [
"bit-manipulation"
],
"difficulty": 6
}
],
"foregone": [
8 changes: 7 additions & 1 deletion exercises/Exercises.sln
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31808.319
@@ -357,6 +357,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StateOfTicTacToe", "practic
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BottleSong", "practice\bottle-song\BottleSong.csproj", "{6BD384E6-225E-4F8A-856C-3079957C6E36}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntergalacticTransmission", "practice\intergalactic-transmission\IntergalacticTransmission.csproj", "{E81F1BA3-1F99-4DCB-B875-78D1F4750BD5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1063,6 +1065,10 @@ Global
{6BD384E6-225E-4F8A-856C-3079957C6E36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BD384E6-225E-4F8A-856C-3079957C6E36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BD384E6-225E-4F8A-856C-3079957C6E36}.Release|Any CPU.Build.0 = Release|Any CPU
{E81F1BA3-1F99-4DCB-B875-78D1F4750BD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E81F1BA3-1F99-4DCB-B875-78D1F4750BD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E81F1BA3-1F99-4DCB-B875-78D1F4750BD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E81F1BA3-1F99-4DCB-B875-78D1F4750BD5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Instructions

Your job is to help implement the message sequencer to add the parity bit to the messages and the decoder to receive messages.

The entire message, itself, is sequence of a number of bytes.
The transmitters and receivers can only transmit and receive one byte at a time, so parity bit needs to be added every eighth bit.
The algorithm for adding the bits is as follows:
1. Divide the message bits into groups of 7, starting from the left (the message is transmitted from left to right).
2. If the last group has less than 7 bits, append some 0s to pad the group to 7 bits.
3. For each group, determine if there are an odd or even number of 1s.
4. If the group has even number of 1s or none at all, append a 0 to the group. Otherwise, append 1 if there is odd number.

For example, consider the message 0xC0_01_C0_DE.
Writing this out in binary and locating every 7th bit:

```text
C 0 0 1 C 0 D E
1100_0000 0000_0001 1100_0000 1101_1110
↑ ↑ ↑ ↑ (7th bits)
```

The last group has only 4 bits (0b1110), so three 0 bits are appended to make it 7 bits:

```text
| 1100_000 | 0000_000 | 0111_000 | 0001_101 | 1110_000 |
```

The first group contains two 1s (an even number of 1s), so 0 is appended to the group.
The second group has none, so append 0.
The rest have three, so they append 1.

```text
| 1100_0000 | 0000_0000 | 0111_0001 | 0001_1011 | 1110_0001 |
| C 0 | 0 0 | 7 1 | 1 B | E 1 | (in hex)
```

Thus, the transmission sequence is 0xC0_00_71_1B_E1.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Introduction

Trillions upon trillions of messages are exchanged between Earth and the neighboring galaxies every millisecond.
But transmission over such long distances faces many obstacles.
Pesky solar flares, worm holes, temporal distortions, stray forces, heck even the flap of a space butterfly wing can cause a random bit to flip during transmission.
The difference between an "o" and a "k", a "[" and "{" or a cowboy emoji and a clown emoji can have huge ramifications, from missed orders to Galactic Stockmarket crashes.
Comment on lines +3 to +6
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fantastic backstory!

It is thus important for the receiver to know if a message has been corrupted so that the receiver can ask for the message to be sent again.

One day, an important message comes through.
People have just heard about the legend about a way of transmitting in such a way that the receiver can tell when bit flipped ... the parity bit ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I know a better phrasing, but this sentence reads a little weird to me. But we can leave it for now and have others comment on it when we do a prob-specs PR.

141 changes: 141 additions & 0 deletions exercises/practice/intergalactic-transmission/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
###############################
# Core EditorConfig Options #
###############################

; This file is for unifying the coding style for different editors and IDEs.
; More information at:
; https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2017
; https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2017

root = true

[*]
indent_style = space

[IntergalacticTransmission.cs]
indent_size = 4

###############################
# .NET Coding Conventions #
###############################

# Organize usings
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = true

# this. preferences
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion

# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion

# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion

# Modifier preferences
dotnet_style_require_accessibility_modifiers = always:suggestion
dotnet_style_readonly_field = true:suggestion

# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
dotnet_style_prefer_conditional_expression_over_return = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion

###############################
# Naming Conventions #
###############################

# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case

# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const

###############################
# C# Code Style Rules #
###############################

# var preferences
csharp_style_var_for_built_in_types = true:none
csharp_style_var_when_type_is_apparent = true:none
csharp_style_var_elsewhere = true:none

# Expression-bodied members
csharp_style_expression_bodied_methods = true:suggestion
csharp_style_expression_bodied_constructors = true:suggestion
csharp_style_expression_bodied_operators = true:suggestion
csharp_style_expression_bodied_properties = true:suggestion
csharp_style_expression_bodied_indexers = true:suggestion
csharp_style_expression_bodied_accessors = true:suggestion

# Pattern-matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion

# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion

# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion

# Expression-level preferences
csharp_prefer_braces = true:none
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion

###############################
# C# Formatting Rules #
###############################

# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = false
csharp_new_line_before_members_in_anonymous_types = false
csharp_new_line_between_query_expression_clauses = true

# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left

# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false

# Wrapping preferences
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
91 changes: 91 additions & 0 deletions exercises/practice/intergalactic-transmission/.meta/Example.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
public static class IntergalacticTransmission
{
private const byte InitUpperMask = (byte)0xFE;

public static byte[] GetTransmitSequence(byte[] message)
{
List<byte> transmitSeq = new List<byte>();
byte carry = 0;
byte upperMask = InitUpperMask;

for (int i = 0; i < message.Length; i++)
{
if (upperMask == 0)
{
// The carry now contains 7 bits. Flush the carry out.
transmitSeq.Add(AddParity(carry));
carry = 0;
upperMask = 0xFE;
}

int shiftPlaces = byte.TrailingZeroCount(upperMask);
int current = (carry << (8 - shiftPlaces)) | (message[i] >>> shiftPlaces);
transmitSeq.Add(AddParity((byte)current));

// Update parameters for next round.
carry = (byte)(message[i] & (~upperMask));

// Shorten the upper mask.
upperMask = (byte)(upperMask << 1);
}

if (upperMask != InitUpperMask)
{
byte lastGroup = (byte)(carry << byte.PopCount(upperMask));
// We have left over carry data
transmitSeq.Add(AddParity(lastGroup));
}
return transmitSeq.ToArray();
}

private static byte AddParity(byte source)
{
if (byte.PopCount((byte)(source & 0x7F)) % 2 == 0)
{
return (byte)(source << 1);
}
return (byte)((source << 1) | 1);
}

public static byte[] DecodeSequence(byte[] receivedSeq)
{
if (receivedSeq.Length == 0)
{
return [];
}

List<byte> decodedMessage = new List<byte>();
byte byteToAdd = 0x00;
byte upperMask = 0xFF;
for (int i = 0; i < receivedSeq.Length; i++)
{
if (upperMask == 0xFF)
{
// We've completed a complete round.
// Current byte too short.
byteToAdd = GetByteData(receivedSeq[i]);
upperMask = 0x80;
continue;
}

byte currentByteData = GetByteData(receivedSeq[i]);
byte contribution = (byte)(currentByteData >>> byte.TrailingZeroCount(upperMask));
decodedMessage.Add((byte)(byteToAdd | contribution));

// Update parameters for next round
byteToAdd = (byte)((currentByteData & ~(upperMask | 0x01)) << byte.PopCount(upperMask));
upperMask = (byte)((upperMask >> 1) | 0x80);
}
return decodedMessage.ToArray();
}

private static byte GetByteData(byte data)
{
if (byte.PopCount(data) % 2 != 0)
{
throw new ArgumentException("Byte has incorrect parity");
}

return (byte)(data & 0xFE);
}
}
17 changes: 17 additions & 0 deletions exercises/practice/intergalactic-transmission/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"authors": [
"kahgoh"
],
"files": {
"solution": [
"IntergalacticTransmission.cs"
],
"test": [
"IntergalacticTransmissionTests.cs"
],
"example": [
".meta/Example.cs"
]
},
"blurb": "Help detect errors in transmissions to neighboring galaxies"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
public static class IntergalacticTransmission
{
public static byte[] GetTransmitSequence(byte[] message)
{
throw new NotImplementedException("You need to implement this method.");
}

public static byte[] DecodeSequence(byte[] receivedSeq)
{
throw new NotImplementedException("You need to implement this method.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="xunit.v3" Version="1.1.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.1" />
<PackageReference Include="Exercism.Tests.xunit.v3" Version="0.1.0-beta1" />
</ItemGroup>
</Project>
Loading

Unchanged files with check annotations Beta

if (count == 0 || count > 6)
{
inListAfter = list;
return null;

Check warning on line 53 in exercises/practice/markdown/Markdown.cs

GitHub Actions / test

Possible null reference return.

Check warning on line 53 in exercises/practice/markdown/Markdown.cs

GitHub Actions / test

Possible null reference return.
}
var headerTag = "h" + count;
}
inListAfter = list;
return null;

Check warning on line 90 in exercises/practice/markdown/Markdown.cs

GitHub Actions / test

Possible null reference return.

Check warning on line 90 in exercises/practice/markdown/Markdown.cs

GitHub Actions / test

Possible null reference return.
}
private static string ParseParagraph(string markdown, bool list, out bool inListAfter)
public int Id { get; set; }
public int ParentId { get; set; }
public List<Tree> Children { get; set; }

Check warning on line 12 in exercises/practice/tree-building/TreeBuilding.cs

GitHub Actions / test

Non-nullable property 'Children' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 12 in exercises/practice/tree-building/TreeBuilding.cs

GitHub Actions / test

Non-nullable property 'Children' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
public bool IsLeaf => Children.Count == 0;
}
private static CultureInfo CreateCulture(string cur, string loc)
{
string curSymb = null;

Check warning on line 26 in exercises/practice/ledger/Ledger.cs

GitHub Actions / test

Converting null literal or possible null value to non-nullable type.
int curNeg = 0;
string datPat = null;

Check warning on line 28 in exercises/practice/ledger/Ledger.cs

GitHub Actions / test

Converting null literal or possible null value to non-nullable type.
if (cur != "USD" && cur != "EUR")
{
}
var culture = new CultureInfo(loc, false);
culture.NumberFormat.CurrencySymbol = curSymb;

Check warning on line 73 in exercises/practice/ledger/Ledger.cs

GitHub Actions / test

Possible null reference assignment.
culture.NumberFormat.CurrencyNegativePattern = curNeg;
culture.DateTimeFormat.ShortDatePattern = datPat;

Check warning on line 75 in exercises/practice/ledger/Ledger.cs

GitHub Actions / test

Possible null reference assignment.
return culture;
}