42
\$\begingroup\$

This is my first challenge on ppcg!

Input

A string consisting of two different ascii characters. For example

ABAABBAAAAAABBAAABAABBAABA

Challenge

The task is to decode this string following these rules:

  1. Skip the first two characters
  2. Split the rest of the string into groups of 8 characters
  3. In each group, replace each character with 0 if that character is the same as the first character of the original string, and with 1 otherwise
  4. Now each group represents a byte. Convert each group to character from byte char code
  5. Concatenate all characters

Example

Let's decode the above string.

 AB  AABBAAAA  AABBAAAB  AABBAABA
 ^^     ^         ^         ^
 |      |         |         |
 |      \---------|---------/
 |                |
Skip      Convert to binary

Notice that A is the first character in the original string and B is the second. Therefore, replace each A with 0 and each B with 1. Now we obtain:

00110000  00110001  00110010

which is [0x30, 0x31, 0x32] in binary. These values represent characters ["0", "1", "2"] respectively, so the final output should be 012.

Scoring

This is, of course, , which means make your code as short as possible. Score is measured in bytes.

Constraints and IO format

Standard rules apply. Here are some additional rules:

  • You can assume valid input
    • Input string consists of exactly two different characters
    • The first two characters are different
    • The minimal length of the input string is 2 characters
    • The length will always give 2 modulo 8
  • You can assume the string will always consist only of printable ASCII characters
    • Both in the input and in the decoded string
  • Leading and trailing whitespace are allowed in the output (everything that matches /\s*/)
\$\endgroup\$
5
  • 6
    \$\begingroup\$ Gotta say man, for a first challenge, this is one of the better formatted challenges I've ever seen. As an fyi, the community sandbox is a great place for feedback before posting so you don't get randomly rep bombed for a rule you didn't know. \$\endgroup\$ Commented Apr 23, 2018 at 0:16
  • \$\begingroup\$ @MagicOctopusUrn. Thank you! Didn't know about sandbox, I'll post there next time :) \$\endgroup\$
    – user80067
    Commented Apr 23, 2018 at 0:18
  • 2
    \$\begingroup\$ I mostly use it so people can call me out on duplicate questions, very simple to follow rules, rather hard to know about dupes without memorizing meta :). I'd also recommend checking out the chatrooms, we have chats for almost every language you could hope to learn and questions are encouraged. \$\endgroup\$ Commented Apr 23, 2018 at 0:18
  • 1
    \$\begingroup\$ Great first challenge! Some more test cases would be neat. \$\endgroup\$
    – lynn
    Commented Apr 23, 2018 at 16:33
  • \$\begingroup\$ Really nice first challenge. Had fun playing with this one. \$\endgroup\$
    – ElPedro
    Commented Apr 23, 2018 at 19:18

44 Answers 44

1
2
1
\$\begingroup\$

C++, 181 Bytes (VS 2017)

#include<iostream>
int main(int,char**a){int c=7;uint8_t b=0;for(int i=2;a[1][i]!='\0';++i,--c){if(a[1][i]!=a[1][0]){b|=(1<<c);}if(c==0){std::cout<<static_cast<char>(b);c=8;b=0;}}}

Formatted, with better variable names and comments:

#include <iostream>

int main(int argc, char* argv[])
{
  int counter = 7;
  uint8_t byte = 0;

  // Loop until input string is fully read
  for (int i = 2; argv[1][i] != '\0'; ++i, --counter)
  {
    if (argv[1][i] != argv[1][0])
    {
      byte |= (1 << counter); // Shift 2^counter into the current byte
    }

    if (counter == 0)
    {
      std::cout << static_cast<char>(byte); // 
      counter = 8;
      byte = 0;
    }
  }
}
\$\endgroup\$
3
  • \$\begingroup\$ Welcome to PPCG! \$\endgroup\$
    – Laikoni
    Commented Apr 27, 2018 at 22:49
  • \$\begingroup\$ @Laikoni Thank you :), I will definitely try some more in the future! \$\endgroup\$
    – Mario
    Commented Apr 27, 2018 at 22:53
  • \$\begingroup\$ Have fun! :) You might be interested in the collection of tips for golfing in C++. \$\endgroup\$
    – Laikoni
    Commented Apr 27, 2018 at 22:56
1
\$\begingroup\$

K4, 22 21 bytes

Solution:

"c"$2/:'0N 8#?/0 2_x:

Example:

q)k)"c"$2/:'0N 8#?/0 2_x:"ABAABBAAAAAABBAAABAABBAABA"
"012"

Explanation:

Evaluated right-to-left:

"c"$2/:'0N 8#?/0 2_x: / the solution
                  x:  / save input as x
               0 2_   / cut x at 0 and 2nd index
             ?/       / lookup (?) over (/)
        0N 8#         / reshape into 8-long rows
    2/:'              / decode (/:) each (') from base 2
"c"$                  / cast to character

Notes:

  • -1 byte thanks to ngn!
\$\endgroup\$
1
  • 1
    \$\begingroup\$ x[1]=2_x: -> ?/0 2_ \$\endgroup\$
    – ngn
    Commented Jun 2, 2018 at 17:57
0
\$\begingroup\$

Charcoal, 17 bytes

F⪪E✂θ²Lθ¹⌕θι⁸℅↨ι²

Try it online! Link is to verbose version of code. Explanation:

   ✂θ²Lθ¹           Slice first two characters from input
  E      ⌕θι        Replace each character with its index in the input
 ⪪          ⁸       Split into groups of 8
F                   Loop over each group
              ↨ι²   Convert from binary
             ℅      Convert from code to character
                    Implicitly print
\$\endgroup\$
0
\$\begingroup\$

Jelly, 8 bytes

ṫ3nḢs8ḄỌ

Try it online!

ṫ3nḢs8ḄỌ
ṫ3        All but first two characters...
  n       does not equal...
   Ḣ      the first character.
    s8    Split into groups of 8.
      Ḅ   Convert from binary (vectorizes).
       Ọ  chr() (vectorizes).
\$\endgroup\$
0
\$\begingroup\$

Jelly, 7 bytes

ḢnḊs8ḄỌ

Try it online!

Who needs (tail)?

Coincidentally Because there is only one way to do it, the 4 last bytes are identical to dylnan's answer.


Actually there is another way, providing there are no leading NUL bytes in the output:

Jelly, 7 bytes

ḢnḊḄb⁹Ọ

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Perl 6, 59 bytes

{/(..)(.**8)*/;$1>>.trans(~$0=>"01")>>.parse-base(2)>>.chr}

Try it online!

Matches the pattern first, then uses a transliteration to 01 and parses the number.

\$\endgroup\$
0
\$\begingroup\$

C (gcc), 94 86 bytes (107 for leading whitespace)

Thanks to Jonathan Frech for saving 8 bytes!

f(s,v,i,j)char*s,*v;{for(v=++s,i=j=0;*++s;j&7||(putchar(i),i=0))i|=!(*s-*v)<<(--j&7);}

Try it online!


Original solution:

f(s,v,i,j)char*s,*v;{for(v=++s,i=j=0;*++s;){i|=!(*s-*v)<<(--j&7);if(!(j&7)){putchar(i);i=0;}}}

Try it online!

This assumes that main()'s stripping of whitespace is allowable. Otherwise, I got it to 107 bytes:

f(s,v,i,j)char*s,*v;{while(*s++<33);for(v=s,i=j=0;*++s;){i|=!(*s-*v)<<(--j&7);if(!(j&7)){putchar(i);i=0;}}}

Try it online!

\$\endgroup\$
4
  • 1
    \$\begingroup\$ 86 bytes. \$\endgroup\$ Commented Apr 23, 2018 at 13:59
  • \$\begingroup\$ @JonathanFrech that's great! My brain hurts when looking at implicit if's, though. :-) \$\endgroup\$
    – ErikF
    Commented Apr 23, 2018 at 23:09
  • \$\begingroup\$ Implicit if's? You mean the short-circuiting or evaluation? \$\endgroup\$ Commented Apr 24, 2018 at 10:23
  • \$\begingroup\$ Here my take at golfing it j,v,i;f(char*s){for(v=*++s;*++s;--j&7||putchar(i))i=2*i|*s==v;}. \$\endgroup\$
    – Christoph
    Commented Apr 25, 2018 at 13:13
0
\$\begingroup\$

C (tcc), 134 bytes

f(char*x){
    int a=*x,i,l=strlen(x);
    for(i=2;i<l;)
        x[i] = x[i++] - a ? 49 : 48;
    for(i=10;i<=l;i+=8)
        a=x[i],
        x[i]=0,
        putchar(strtol(x+i-8,0,2)),
        x[i]=a;
}

Try it online!

I am still trying to think of a better way than that ugly swap :P

\$\endgroup\$
0
\$\begingroup\$

Rust, 166 bytes

fn x(x:&str){for i in(2..x.len()-2).step_by(8){print!("{}",u8::from_str_radix(&x[i..i+8].chars().map(|c|(c as u8-17)as char).collect::<String>(),2).unwrap()as char)}}

Playground

Playground link because it requires nightly and tio seems to use stable.

\$\endgroup\$
0
\$\begingroup\$

Perl 6, 82 bytes 79 bytes

{.[2..*].map({+($^s ne.[0])}).rotor(8)».join».parse-base(2)».chr with .comb}

Shortened with help from Phil H (but his solution is still shorter, so go look at his one)

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ You can shorten the block inside the map by just casting a bool to a number: {+($^s ne.[0])} \$\endgroup\$
    – Phil H
    Commented Apr 23, 2018 at 21:35
0
\$\begingroup\$

Coconut, 71 bytes

s->k(chr..int$(?,2)..k$(str..s.index),groupsof(8,s[2:]))
k=''.join..map

Try it online!

\$\endgroup\$
0
\$\begingroup\$

GolfScript, 24 bytes

1>(:x;8/{{x=}%2base}%''+

Try it online!

Explanation:

1>(:x;8/{{x=}%2base}%''+ Full program, implicit input.
                         Stack: "ABAABBAAAAAABBAAABAABBAABA"
1>                       Pop the first character (str[1:])
                         Stack: "BAABBAAAAAABBAAABAABBAABA"
  (:x;                   Pop the next character and assign it to x
                         Stack: "AABBAAAAAABBAAABAABBAABA"; x = 66
      8/                 Split into groups of 8
                         Stack: ["AABBAAAA" "AABBAAAB" "AABBAABA"]; x = 66
        {          }%    Map
                           Stack (first run): "AABBAAAA"; x = 66
         {  }%             Map again
                             Stack (first run): 65; x = 66
          x=                 Compare to x
                             Stack: 0; x = 66
                           Stack: [0 0 1 1 0 0 0 0]; x = 66
                           Well, actually, it is a string of 0 and 1 bytes.
              2base        Convert binary string to number
                           Stack: 48; x = 66
                         Stack: [48 49 50]; x = 66
                     ''+ Convert to string
                         Stack: "012"; x = 66
                         Implicit output
\$\endgroup\$
0
\$\begingroup\$

bash + bc + xxd, 87 bytes

a="${1:2:${#1}}"
b="${a//${1::1}/0}"
bc<<<"obase=16;ibase=2;${b//${1:1:1}/1}"|xxd -r -p

Usage:

bash foo.bash 'ABAABBAAAAAABBAAABAABBAABA'
\$\endgroup\$
0
\$\begingroup\$

Thunno 2 B, 9 bytes

Ḣsḣ8ẇQ2ȷḋ

Try it online!

Explanations

Ḣsḣ8ẇQ2ȷḋ  # Implicit input, converted to charcodes
Ḣ          # Extract the first character from the input
 sḣ        # And remove the next character from the rest
   8ẇ      # Split it into groups of eight
     Q     # For each: is it not equal to the first character
       ȷ   # For each inner list in this nested list:
      2 ḋ  # Convert it back from binary to decimal
           # Implicit output, converted to characters

Old:

2ɱ$2ỵ8ẇsȷbC  # Implicit input
2ɱ           # Take the first two characters
  $2ỵ        # And then push the rest of the string
     8ẇ      # Split it into groups of eight
       sȷb   # Convert each from base-(first two characters)
          C  # Convert to characters
             # Implicit output
\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.