6
\$\begingroup\$

ADFGX cipher encryption

The ADFGX cipher was used by the German army in WWI. Write a program to encipher with it!

It works as follows:

  1. Create a 5x5 Polybius square with a mixed alphabet. The polybias square is labled A D F G X along the top and left.
  2. Generate the pairs, so A in its non-mixed position is AA, B is AD and so on.
  3. Perform columnar transposition using the columnar key.
  4. Output the ciphertext.

Rules

  • Your program should either define a function that accepts the arguments of the mixed alphabet and the columnar transposition key, in that order, or accept the alphabet/key as command-line arguments. You can also get input from STDIN.
  • Standard loopholes apply.
  • You can't use a pre-written columnar transposition library (or, for that matter, ADFGX) - i.e. no running something like import cipherpack.

Scoring

This is , so shortest code (in bytes) wins!

Test cases

My example runs used a failed source. I'll do some more later.

Leaderboard

Run the Stack Snippet to generate a leaderboard.

/* Configuration */

var QUESTION_ID = 71997; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 50171; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
  return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function commentUrl(index, answers) {
  return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;
}

function getAnswers() {
  jQuery.ajax({
    url: answersUrl(answer_page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      answers_hash = [];
      answer_ids = [];
      data.items.forEach(function(a) {
        a.comments = [];
        var id = +a.share_link.match(/\d+/);
        answer_ids.push(id);
        answers_hash[id] = a;
      });
      if (!data.has_more) more_answers = false;
      comment_page = 1;
      getComments();
    }
  });
}

function getComments() {
  jQuery.ajax({
    url: commentUrl(comment_page++, answer_ids),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      data.items.forEach(function(c) {
        if (c.owner.user_id === OVERRIDE_USER)
          answers_hash[c.post_id].comments.push(c);
      });
      if (data.has_more) getComments();
      else if (more_answers) getAnswers();
      else process();
    }
  });  
}

getAnswers();

var SCORE_REG = /<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
  return a.owner.display_name;
}

function process() {
  var valid = [];
  
  answers.forEach(function(a) {
    var body = a.body;
    a.comments.forEach(function(c) {
      if(OVERRIDE_REG.test(c.body))
        body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
    });
    
    var match = body.match(SCORE_REG);
    if (match)
      valid.push({
        user: getAuthorName(a),
        size: +match[2],
        language: match[1],
        link: a.share_link,
      });
    
  });
  
  valid.sort(function (a, b) {
    var aB = a.size,
        bB = b.size;
    return aB - bB
  });

  var languages = {};
  var place = 1;
  var lastSize = null;
  var lastPlace = 1;
  valid.forEach(function (a) {
    if (a.size != lastSize)
      lastPlace = place;
    lastSize = a.size;
    ++place;
    
    var answer = jQuery("#answer-template").html();
    answer = answer.replace("{{PLACE}}", lastPlace + ".")
                   .replace("{{NAME}}", a.user)
                   .replace("{{LANGUAGE}}", a.language)
                   .replace("{{SIZE}}", a.size)
                   .replace("{{LINK}}", a.link);
    answer = jQuery(answer);
    jQuery("#answers").append(answer);

    var lang = a.language;
    if (/<a/.test(lang)) lang = jQuery(lang).text();
    
    languages[lang] = languages[lang] || {lang: a.language, user: a.user, size: a.size, link: a.link};
  });

  var langs = [];
  for (var lang in languages)
    if (languages.hasOwnProperty(lang))
      langs.push(languages[lang]);

  langs.sort(function (a, b) {
    if (a.lang > b.lang) return 1;
    if (a.lang < b.lang) return -1;
    return 0;
  });

  for (var i = 0; i < langs.length; ++i)
  {
    var language = jQuery("#language-template").html();
    var lang = langs[i];
    language = language.replace("{{LANGUAGE}}", lang.lang)
                       .replace("{{NAME}}", lang.user)
                       .replace("{{SIZE}}", lang.size)
                       .replace("{{LINK}}", lang.link);
    language = jQuery(language);
    jQuery("#languages").append(language);
  }

}
body { text-align: left !important}

#answer-list {
  padding: 10px;
  width: 290px;
  float: left;
}

#language-list {
  padding: 10px;
  width: 290px;
  float: left;
}

table thead {
  font-weight: bold;
}

table td {
  padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">
<div id="answer-list">
  <h2>Leaderboard</h2>
  <table class="answer-list">
    <thead>
      <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
    </thead>
    <tbody id="answers">

    </tbody>
  </table>
</div>
<div id="language-list">
  <h2>Winners by Language</h2>
  <table class="language-list">
    <thead>
      <tr><td>Language</td><td>User</td><td>Score</td></tr>
    </thead>
    <tbody id="languages">

    </tbody>
  </table>
</div>
<table style="display: none">
  <tbody id="answer-template">
    <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>
<table style="display: none">
  <tbody id="language-template">
    <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>

Note:

It is not necessary to split the output into groups of five.

\$\endgroup\$
  • 1
    \$\begingroup\$ Wouldn't B in its non-mixed position be AD, not AB? \$\endgroup\$ – Doorknob Feb 13 '16 at 15:26
  • \$\begingroup\$ Also, does it need to be case insensitive or can we assume all input is in uppercase? Could we have some test cases? \$\endgroup\$ – Doorknob Feb 13 '16 at 15:30
  • \$\begingroup\$ Also, you never specified where the actual message to encipher comes in the input. Does it come first (before the alphabet and the key) or last (after them)? \$\endgroup\$ – Doorknob Feb 13 '16 at 15:33
  • 1
    \$\begingroup\$ Do we need to separate the ciphertext into groups of five? \$\endgroup\$ – lirtosiast Feb 13 '16 at 16:07
  • \$\begingroup\$ @Doorknob Yes, I've updated the question. I'll do some test cases when I'm on my PC. \$\endgroup\$ – bob Feb 13 '16 at 16:09
4
\$\begingroup\$

Pyth, 26 bytes

seMhDC,Q.TcsXwz^"ADFGX"2lQ

For this, the second line (columnar key) needs to be in quotes, which is acceptable by default.

Try it here.

\$\endgroup\$
4
\$\begingroup\$

Pyth, 36 34 33 32 31 bytes

JwseMhDC,J.Tcsm@^"ADFGX"2xzdwlJ
Jw                                assign (z, J) to 2 lines of input
              m             w     map over each char of a 3rd input line...
                ^"ADFGX"2         generate ['AA', 'AD', 'AF', ...]
                         xzd      find the index of this char in z
               @                  index into ^^ with ^
             s                    join groups of 2 ch. into one string
            c                lJ   split ^ into groups of len(J) chars
          .T                      transpose
       C,J                        pair elems up with chars of J
     hD                           sort by chars of J (the key)
   eM                             get rid of the chars of J now
  s                               join

Thanks to Thomas Kwa for a byte!

Sample run, using the example from Wikipedia:

llama@llama:~$ pyth -c 'JwjdeMhDC,J.Tcsm@^"ADFGX"2xzdwlJ'
BTALPDHOZKQFVSNGJCUXMREWY
CARGO
ATTACKATONCE
FAXDF ADDDG DGFFF AFAX AFAFX
\$\endgroup\$
  • \$\begingroup\$ Sorry for posting a similar solution, and thanks for linking to the test case. \$\endgroup\$ – lirtosiast Feb 13 '16 at 16:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.