DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #299 - Time to Grille!

A grille cipher was a technique for encrypting plaintext by writing it onto a sheet of paper through a pierced sheet. The earliest known use is from the mathematician Girolamo Cardano in 1550. His proposal was for a rectangular stencil allowing single letters, syllables, or words to be written, then later read. The written fragments of the plaintext could be further disguised by filling the gaps between the fragments with benign words or letters.

Wikipedia: https://en.wikipedia.org/wiki/Grille_(cryptography)

Write a function that accepts two inputs: message and code. Code is a non-negative integer and should be converted to binary. Overlay the code converted to binary and the message to reveal the result.

Example

Grille("abcdef", 5)  => "df"

* convert 5 to binary:
 000101

* overlay message and code:
message : abcdef
code    : 000101
----------------
result  : df
Enter fullscreen mode Exit fullscreen mode

Tests

Grille("0abc", 2)

Grille("abcde", 32)

Grille("abcd", 1)

Good luck!


This challenge comes from dcieslak on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Top comments (8)

Collapse
 
_bkeren profile image
''

JS


const dec2bin = dec => (dec >>> 0).toString(2);

const Grille = (message, code) => {
  const codeToBinary= dec2bin(code).padStart(message.length, "0")
  return codeToBinary.split("")
    .map((binaryLetter, index) => binaryLetter === "1" ? index : '')
    .filter(String)
    .map(index => message.charAt(index)).join("")
}

Enter fullscreen mode Exit fullscreen mode
Collapse
 
celyes profile image
Ilyes Chouia • Edited

This is the solution in PHP, but I'm not sure if it's 100% correct since there aren't enough test cases and the test cases provided above don't have the result so they're pretty much useless.
anyway, here's my attempt:

function grille($message, $code)
{
    $letters = '';
    $code = array_filter(str_split(sprintf("%06d", decbin($code))), function($x) {
        return $x == 1;
    });
    $code = array_keys($code);
    foreach(str_split($message) as $index => $letter){
        if(in_array($index, $code)){
            $letters .= $letter;
        }
    }
    return $letters;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
peter279k profile image
peter279k

Here is the simple solution with Python:

def grille(message, code):
    bin_number = bin(code)[2:]
    bin_number_len = len(bin_number)

    if len(message) <= 1:
        return ''
    if len(message) > bin_number_len:
        bin_number = ('0' * (len(message) - bin_number_len)) + bin_number

    index = 0
    result = ''
    while index < len(message):
        if bin_number[index] == '1':
            result += message[index]
        index += 1

    if len(message) < bin_number_len:
        if len(result) == len(message):
            return result
        else:
            return ''

    return result

Enter fullscreen mode Exit fullscreen mode
Collapse
 
agtoever profile image
agtoever

Python 3-liner with test cases and TIO link.
Apart from some type conversions, itertools.compress does the job.

import itertools
filterlist = lambda value, length: map(int, bin(value)[2:].zfill(length))
grille = lambda string, grille: ''.join(itertools.compress(string, filterlist(grille, len(string))))

cases = [
    ('abcdef', 5),
    ('0abc', 2),
    ('abcde', 32),
    ('abcd', 1)
]
for case in cases:
    print(f'grille{case} has filter {list(filterlist(case[1], len(case[0])))} and outcome: {grille(*case)}')
Enter fullscreen mode Exit fullscreen mode

Try it online!

Collapse
 
rafaacioly profile image
Rafael Acioly • Edited

Scala solution

def grille(text: String, code: Int) = {
  val letters = text.split("")
  val digits = code.toBinaryString.map(_.asDigit)

  val res = letters.toList.reverse.zipAll(digits, 0, 0)

  (res collect { case (i, v) if v != 0 => i }).mkString("")
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
biancapower profile image
Bianca Power

ruby

def grille(message, code)
  output = ""

  # convert code to binary
  binary_code = code.to_s(2)

  # prepend the appropriate number of zeros to match length of message
  while message.length > binary_code.length
    binary_code.prepend('0')
  end

  # combine messages and binary_code into a hash
  arrays_hash = Hash[message.split("").zip(binary_code.split(""))]

  # if the value is 1, add the key to the output string
  arrays_hash.each do |k, v|
    if v == "1"
      output << k
    end
  end

  return output
end
Enter fullscreen mode Exit fullscreen mode
Collapse
 
wheatup profile image
Hao • Edited

Another JavaScript solution, using binary operations:

const Grille = (str, bin) => [...str].filter((_, i) => 1 << (str.length-i-1) & bin).join('');
Enter fullscreen mode Exit fullscreen mode
Collapse
 
bugb profile image
bugb • Edited

JS solution

Grille=(m,c)=>[...m].filter((o,i)=>+[...c.toString(2).padStart(m.length,0)][i]).join``
Enter fullscreen mode Exit fullscreen mode