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\$
6
  • 1
    \$\begingroup\$ Wouldn't B in its non-mixed position be AD, not AB? \$\endgroup\$
    – Doorknob
    Feb 13, 2016 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, 2016 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, 2016 at 15:33
  • 1
    \$\begingroup\$ Do we need to separate the ciphertext into groups of five? \$\endgroup\$
    – lirtosiast
    Feb 13, 2016 at 16:07
  • \$\begingroup\$ @Doorknob Yes, I've updated the question. I'll do some test cases when I'm on my PC. \$\endgroup\$
    – user50171
    Feb 13, 2016 at 16:09

2 Answers 2

3
\$\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\$
3
\$\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\$
1
  • \$\begingroup\$ Sorry for posting a similar solution, and thanks for linking to the test case. \$\endgroup\$
    – lirtosiast
    Feb 13, 2016 at 16:43

Your Answer

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