⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

{{task|Encryption}}

;Task: Implement functions to encrypt and decrypt a message using the [[wp:Straddling_checkerboard|straddling checkerboard]] method. The checkerboard should take a 28 character alphabet (A-Z plus a full stop and an escape character) and two different numbers representing the blanks in the first row. The output will be a series of decimal digits.

Numbers should be encrypted by inserting the escape character before each digit, then including the digit unencrypted. This should be reversed for decryption.

ALGOL 68

{{trans|C++}} Note: This specimen retains the original [[#C++|C++]] coding style. {{works with|ALGOL 68|Revision 1 - no extensions to language used.}} {{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny].}} {{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}}

#!/usr/local/bin/a68g --script #

PRIO MIN=5, MAX=5;
OP MIN = (INT a, b)INT: (a<b|a|b),
   MAX = (INT a, b)INT: (a>b|a|b);

MODE STRADDLINGCHECKERBOARD=STRUCT(
  [0:9]CHAR first, second, third,
  [ABS ".": ABS "Z"]STRING table,
  INT row u, row v,
  CHAR esc, skip
);

STRUCT(
  PROC (REF STRADDLINGCHECKERBOARD #self#, STRING #alphabet#, INT #u#, INT #v#)VOID init,
  PROC (REF STRADDLINGCHECKERBOARD #self#, STRING #plain#)STRING encode,
  PROC (REF STRADDLINGCHECKERBOARD #self#, STRING #plain#)STRING decode
) sc class = (
# PROC init = # (REF STRADDLINGCHECKERBOARD self, STRING in alphabet, INT u, v)VOID:
  (
    STRING alphabet = in alphabet[@0];

    esc OF self := alphabet[UPB alphabet]; # use the last CHAR as the escape #
    skip OF self := alphabet[UPB alphabet-1];

    row u OF self := u MIN v;
    row v OF self := u MAX v;

    OP DIGIT = (INT i)CHAR: REPR(ABS "0" + i );

    INT j := LWB alphabet;

  # (first OF self)[u] := (first OF self)[v] := skip; #

    FOR i FROM LWB first OF self TO UPB first OF self  DO
      IF i NE u AND i NE v THEN
        (first OF self)[i] := alphabet[j];
        (table OF self)[ABS alphabet[j]] := DIGIT i;
        j+:=1
      FI;

      (second OF self)[i] := alphabet[i+8];
      (table OF self)[ABS alphabet[i+8]] := DIGIT (row u OF self) + DIGIT i;

      (third OF self)[i] := alphabet[i+18];
      (table OF self)[ABS alphabet[i+18]] := DIGIT (row v OF self) + DIGIT i
    OD
  ),

# PROC encode = # (REF STRADDLINGCHECKERBOARD self, STRING plain)STRING:
  (
    STRING esc = (table OF self)[ABS (esc OF self)];
    INT l2u = ABS "A" - ABS "a";

    STRING out := "";
    FOR i FROM LWB plain TO UPB plain DO
      CHAR c := plain[i];
      IF "a" <= c AND c <= "z" THEN
        c := REPR ( ABS c + l2u) FI;

      IF "A" <= c AND c <= "Z" THEN
        out +:= (table OF self)[ABS c]
      ELIF "0" <= c AND c <= "9" THEN
        out +:= esc + c
      FI
    OD;
    out # EXIT #
  ),

# PROC decode = # (REF STRADDLINGCHECKERBOARD self, STRING cipher)STRING:
  (
    CHAR null = REPR 0;
    STRING out;
    INT state := 0;
    FOR i FROM LWB cipher TO UPB cipher DO
      INT n := ABS cipher[i] - ABS "0";

      CHAR next :=
        CASE state IN
          #1:# (second OF self)[n],
          #2:# (third OF self)[n],
          #3:# cipher[i]
        OUT
          IF n = row u OF self THEN
            state := 1; null
          ELIF n = row v OF self THEN
            state := 2; null
          ELSE
            (first OF self)[n]
          FI
        ESAC;

      IF next = "/" THEN
        state := 3
      ELIF next NE null THEN
        state := 0;
        out +:= next
      FI
    OD;
    out # EXIT #
  )
);

main:
(
  STRADDLINGCHECKERBOARD sc; (init OF sc class)(sc, "HOLMESRTABCDFGIJKNPQUVWXYZ./", 3, 7);

  STRING original := "One night-it was on the twentieth of March, 1888-I was returning"[@0];
  STRING en := (encode OF sc class)(sc, original);
  STRING de := (decode OF sc class)(sc, en);

  printf(($ggl$,
          "Original: ", original,
          "Encoded:  ", en,
          "Decoded:  ", de
  ))

)

Output:


Original: One night-it was on the twentieth of March, 1888-I was returning
Encoded:  139539363509369743061399059745399365901344308320791798798798367430685972839363935
Decoded:  ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING

AutoHotkey

board := "
(
ET AON RIS
BCDFGHJKLM
PQ/UVWXYZ.
)"
Text = One night-it was on the twentieth of March, 1888-I was returning
StringUpper, Text, Text
Text := RegExReplace(text, "[^A-Z0-9]")
Num2 := InStr(board, A_Space)               -1
Num3 := InStr(board, A_Space, true, Num1+1) -1
Loop Parse, Text
{
	char := A_LoopField
	Loop Parse, board, `n
	{
		If (Pos := InStr(A_LoopField, char))
			out .= Num%A_Index% . Pos-1
		else if (Pos := InStr(A_LoopField, "/")) && InStr("0123456789", char)
			out .= Num%A_Index% . Pos-1 . char
	}
}
MsgBox % out

i := 0
While (LoopField := SubStr(out, ++i, 1)) <> ""
{
	If (LoopField = num2) or (LoopField = num3)
		col := SubStr(out, ++i, 1)
	else	col := 0
	Loop Parse, board, `n
	{
		If !col && A_Index = 1
			dec .= SubStr(A_LoopField, LoopField+1, 1)
		Else If (Num%A_Index% = LoopField) && col
			dec .= SubStr(A_LoopField, col+1, 1)
		If SubStr(dec, 0) = "/"
			dec := SubStr(dec, 1, StrLen(dec)-1) . SubStr(out, ++i, 1)
	}
}
MsgBox % dec

C

{{libheader|GLib}}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <glib.h>

#define ROWS   4
#define COLS  10
#define NPRX  "/"

/* wikipedia table
const char *table[ROWS][COLS] =
{
  { "0", "1", "2",  "3", "4", "5", "6",  "7", "8", "9" },
  { "E", "T", NULL, "A", "O", "N", NULL, "R", "I", "S  },
  { "B", "C", "D",  "F", "G", "H", "J",  "K", "L", "M" },
  { "P", "Q", NPRX, "U", "V", "W", "X",  "Y", "Z", "." }
};
*/

/* example of extending the table, COLS must be 11
const char *table[ROWS][COLS] =
{
  { "0", "1", "2", "3",  "4", "5", "6", "7",  "8", "9",  ":"  },
  { "H", "O", "L", NULL, "M", "E", "S", NULL, "R", "T",  ","  },
  { "A", "B", "C", "D",  "F", "G", "I", "J",  "K", "N",  "-"  },
  { "P", "Q", "U", "V",  "W", "X", "Y", "Z",  ".", NPRX, "?"  }
};
*/

// task table
const char *table[ROWS][COLS] =
{
  { "0", "1", "2", "3",  "4", "5", "6", "7",  "8", "9"  },
  { "H", "O", "L", NULL, "M", "E", "S", NULL, "R", "T"  },
  { "A", "B", "C", "D",  "F", "G", "I", "J",  "K", "N"  },
  { "P", "Q", "U", "V",  "W", "X", "Y", "Z",  ".", NPRX }
};


GHashTable *create_table_from_array(const char *table[ROWS][COLS], bool is_encoding)
{
  char buf[16];

  GHashTable *r = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
  size_t i, j, k, m;

  for(i = 0, m = 0; i < COLS; i++)
  {
    if (table[1][i] == NULL) m++;
  }

  const size_t SELNUM = m;

  size_t selectors[SELNUM];
  size_t numprefix_row, numprefix_col;
  bool has_numprefix = false;

  // selectors keep the indexes of the symbols to select 2nd and 3rd real row;
  // nulls must be placed into the 2nd row of the table
  for(i = 0, k = 0; i < COLS && k < SELNUM; i++)
  {
    if ( table[1][i] == NULL )
    {
      selectors[k] = i;
      k++;
    }
  }

  // numprefix is the prefix to insert symbols from the 1st row of table (numbers)
  for(j = 1; j < ROWS; j++)
  {
    for(i = 0; i < COLS; i++)
    {
      if (table[j][i] == NULL) continue;
      if ( strcmp(table[j][i], NPRX) == 0 )
      {
        numprefix_col = i;
        numprefix_row = j;
        has_numprefix = true;
	break;
      }
    }
  }

  // create the map for each symbol
  for(i = has_numprefix ? 0 : 1; i < ROWS; i++)
  {
    for(j = 0; j < COLS; j++)
    {
      if (table[i][j] == NULL) continue;
      if (strlen(table[i][j]) > 1)
      {
	fprintf(stderr, "symbols must be 1 byte long\n");
	continue; // we continue just ignoring the issue
      }
      if (has_numprefix && i == (ROWS-1) && j == numprefix_col && i == numprefix_row) continue;
      if (has_numprefix && i == 0)
      {
	snprintf(buf, sizeof(buf), "%s%s%s", table[0][selectors[SELNUM-1]], table[0][numprefix_col], table[0][j]);
      }
      else if (i == 1)
      {
	snprintf(buf, sizeof(buf), "%s", table[0][j]);
      }
      else
      {
	snprintf(buf, sizeof(buf), "%s%s", table[0][selectors[i-2]], table[0][j]);
      }
      if (is_encoding) g_hash_table_insert(r, strdup(table[i][j]), strdup(buf));
      else g_hash_table_insert(r, strdup(buf), strdup(table[i][j]));
    }
  }
  if (is_encoding) g_hash_table_insert(r, strdup("mode"), strdup("encode"));
  else g_hash_table_insert(r, strdup("mode"), strdup("decode"));

  return r;
}

char *decode(GHashTable *et, const char *enctext)
{
  char *r = NULL;

  if (et == NULL || enctext == NULL || strlen(enctext) == 0 ||
      g_hash_table_lookup(et, "mode") == NULL ||
      strcmp(g_hash_table_lookup(et, "mode"), "decode") != 0) return NULL;

  GString *res = g_string_new(NULL);
  GString *en = g_string_new(NULL);

  for( ; *enctext != '\0'; enctext++ )
  {
    if (en->len < 3)
    {
      g_string_append_c(en, *enctext);
      r = g_hash_table_lookup(et, en->str);
      if (r == NULL) continue;
      g_string_append(res, r);
      g_string_truncate(en, 0);
    }
    else
    {
      fprintf(stderr, "decoding error\n");
      break;
    }
  }

  r = res->str;
  g_string_free(res, FALSE);
  g_string_free(en, TRUE);
  return r;
}

char *encode(GHashTable *et, const char *plaintext, int (*trasf)(int), bool compress_spaces)
{
  GString *s;
  char *r = NULL;
  char buf[2] = { 0 };

  if (plaintext == NULL ||
      et == NULL || g_hash_table_lookup(et, "mode") == NULL ||
      strcmp(g_hash_table_lookup(et, "mode"), "encode") != 0) return NULL;

  s = g_string_new(NULL);

  for(buf[0] = trasf ? trasf(*plaintext) : *plaintext;
      buf[0] != '\0';
      buf[0] = trasf ? trasf(*++plaintext) : *++plaintext)
  {
    if ( (r = g_hash_table_lookup(et, buf)) != NULL )
    {
      g_string_append(s, r);
    }
    else if (isspace(buf[0]))
    {
      if (!compress_spaces) g_string_append(s, buf);
    }
    else
    {
      fprintf(stderr, "char '%s' is not encodable%s\n",
	      isprint(buf[0]) ? buf : "?",
	      !compress_spaces ? ", replacing with a space" : "");
      if (!compress_spaces) g_string_append_c(s, ' ');
    }
  }

  r = s->str;
  g_string_free(s, FALSE);
  return r;
}


int main()
{
  GHashTable *enctab = create_table_from_array(table, true);  // is encoding? true
  GHashTable *dectab = create_table_from_array(table, false); // is encoding? false (decoding)

  const char *text = "One night-it was on the twentieth of March, 1888-I was returning";

  char *encoded = encode(enctab, text, toupper, true);
  printf("%s\n", encoded);

  char *decoded = decode(dectab, encoded);
  printf("%s\n", decoded);

  free(decoded);
  free(encoded);
  g_hash_table_destroy(enctab);
  g_hash_table_destroy(dectab);

  return 0;
}

Shorter version

#include <stdio.h>
#include <stdlib.h>

const char * board =  "ET AON RIS"
                      "BCDFGHJKLM"
                      "PQ/UVWXYZ.";

char encode[128] = {0};
char decode[128] = {0};
int row[2] = {0};

void read_table(const char *s)
{
        int i, code;
        for (i = 0; i < 30; i++) {
                if (s[i] == '\0') {
                        fprintf(stderr, "Table too short\n");
                        exit(1);
                }

                if (s[i] == ' ') {
                        row[  row[0] ? 1 : 0 ] = i;
                        continue;
                }

                code = ((i < 10) ? 0 : i < 20 ? row[0] : row[1])
                                * 10 + (i % 10);
                encode[0 + s[i]] = code; /* guess what 0 + s[i] does, sigh */
                decode[code] = s[i];
        }
}

void encipher(const char *in, char *out, int strip)
{
#define PUTCODE(c) { if (c > 9) {*(out++) = c / 10 + '0'; c %= 10;} *(out++) = c + '0'; }
        int c, code;
        while ((c = *(in++)) != '\0') {
                if (c >= '0' && c <= '9') {
                        code = encode['.'];
                        c -= '0';
                        PUTCODE(code);
                        PUTCODE(c);
                        continue;
                }

                c &= ~0x20;

                if (c >= 'A' && c <= 'Z') code = encode[c];
                else if (strip && !c )    continue;
                else                      code = encode['/'];

                PUTCODE(code);
        }
        *(out++) = '\0';
}

void decipher(const char *in, char *out, int strip)
{
        int c;
        while ((c = *(in++)) != '\0') {
                c -= '0';
                if (c == row[0] || c == row[1])
                        c = c * 10 + *(in++) - '0';

                c = decode[c];

                if (c == '.') c = *(in++);
                if (c == '/' && !strip) c = ' ';
                *(out++) = c;
        }
        *(out++) = '\0';
}

int main()
{
        const char *msg = "In the winter 1965/we were hungry/just barely alive";
        char enc[100] = {0}, dec[100] = {0};
        read_table(board);

        printf("message: %s\n", msg);
        encipher(msg, enc, 0); printf("encoded: %s\n", enc);
        decipher(enc, dec, 0); printf("decoded: %s\n", dec);

        printf("\nNo spaces:\n");
        encipher(msg, enc, 1); printf("encoded: %s\n", enc);
        decipher(enc, dec, 1); printf("decoded: %s\n", dec);
        return 0;
}

Output:message: In the winter 1965/we were hungry/just barely alive encoded: 85621250626585107626916996966956265062650706225635247676226639162203702867623288640 decoded: IN THE WINTER 1965 WE WERE HUNGRY JUST BARELY ALIVE

No spaces: encoded: 851250658510769169969669562650650702563524767622663912037028673288640 decoded: INTHEWINTER1965/WEWEREHUNGRY/JUSTBARELYALIVE




## C#

Translation of [[Straddling_checkerboard#Java|Java]] via [[Straddling_checkerboard#D|D]]

```c#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace StraddlingCheckerboard
{
    class Program
    {
        public readonly static IReadOnlyDictionary<char, string> val2Key;
        public readonly static IReadOnlyDictionary<string, char> key2Val;

        static Program()
        {
            val2Key = new Dictionary<char, string> {
                {'A',"30"},  {'B',"31"}, {'C',"32"},  {'D',"33"},  {'E',"5"},   {'F',"34"},  {'G',"35"},
                {'H',"0"},   {'I',"36"}, {'J',"37"},  {'K',"38"},  {'L',"2"},   {'M',"4"},   {'.',"78"},
                {'N',"39"},  {'/',"79"}, {'O',"1"},   {'0',"790"}, {'P',"70"},  {'1',"791"}, {'Q',"71"},
                {'2',"792"}, {'R',"8"},  {'3',"793"}, {'S',"6"},   {'4',"794"}, {'T',"9"},   {'5',"795"},
                {'U',"72"},  {'6',"796"},{'V',"73"},  {'7',"797"}, {'W',"74"},  {'8',"798"}, {'X',"75"},
                {'9',"799"}, {'Y',"76"}, {'Z',"77"}};

            key2Val = val2Key.ToDictionary(kv => kv.Value, kv => kv.Key);
        }

        public static string Encode(string s)
        {
            return string.Concat(s.ToUpper().ToCharArray()
                .Where(c => val2Key.ContainsKey(c)).Select(c => val2Key[c]));
        }

        public static string Decode(string s)
        {
            return string.Concat(Regex.Matches(s, "79.|7.|3.|.").Cast<Match>()
                .Where(m => key2Val.ContainsKey(m.Value)).Select(m => key2Val[m.Value]));
        }

        static void Main(string[] args)
        {
            var enc = Encode("One night-it was on the twentieth of March, 1888-I was returning");
            Console.WriteLine(enc);
            Console.WriteLine(Decode(enc));

            Console.ReadLine();
        }
    }
}
139539363509369743061399059745399365901344308320791798798798367430685972839363935
ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING

C++

#include <iostream>
#include <string>
#include <map>
#include <algorithm> // for min, max
using namespace std;

class StraddlingCheckerboard
{
  map<char, string> table;
  char first[10], second[10], third[10];
  int rowU, rowV;

public:
  StraddlingCheckerboard(const string &alphabet, int u, int v)
  {
    rowU = min(u, v);
    rowV = max(u, v);

    for(int i = 0, j = 0; i < 10; ++i)
    {
      if(i != u && i != v)
      {
        first[i] = alphabet[j];
        table[alphabet[j]] = '0' + i;
        ++j;
      }

      second[i] = alphabet[i+8];
      table[alphabet[i+8]] = '0' + rowU;
      table[alphabet[i+8]] += '0' + i;

      third[i] = alphabet[i+18];
      table[alphabet[i+18]] = '0' + rowV;
      table[alphabet[i+18]] += '0' + i;
    }
  }

  string encode(const string &plain)
  {
    string out;
    for(int i = 0; i < plain.size(); ++i)
    {
      char c = plain[i];
      if(c >= 'a' && c <= 'z')
        c += 'A' - 'a';

      if(c >= 'A' && c <= 'Z')
        out += table[c];
      else if(c >= '0' && c <= '9')
      {
        out += table['/'];
        out += c;
      }
    }
    return out;
  }

  string decode(const string &cipher)
  {
    string out;
    int state = 0;
    for(int i = 0; i < cipher.size(); ++i)
    {
      int n = cipher[i] - '0';
      char next = 0;

      if(state == 1)
        next = second[n];
      else if(state == 2)
        next = third[n];
      else if(state == 3)
        next = cipher[i];
      else if(n == rowU)
        state = 1;
      else if(n == rowV)
        state = 2;
      else
        next = first[n];

      if(next == '/')
        state = 3;
      else if(next != 0)
      {
        state = 0;
        out += next;
      }
    }
    return out;
  }
};

Test program:

int main()
{
  StraddlingCheckerboard sc("HOLMESRTABCDFGIJKNPQUVWXYZ./", 3, 7);

  string original = "One night-it was on the twentieth of March, 1888-I was returning";
  string en = sc.encode(original);
  string de = sc.decode(en);

  cout << "Original: " << original << endl;
  cout << "Encoded:  " << en << endl;
  cout << "Decoded:  " << de << endl;

  return 0;
}

Output:


Original: One night-it was on the twentieth of March, 1888-I was returning
Encoded:  139539363509369743061399059745399365901344308320791798798798367430685972839363935
Decoded:  ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING

D

Partially based on the PicoLisp version:

import std.stdio, std.algorithm, std.string, std.array;

immutable T = ["79|0|1|2|3|4|5|6|7|8|9", "|H|O|L||M|E|S||R|T",
               "3|A|B|C|D|F|G|I|J|K|N", "7|P|Q|U|V|W|X|Y|Z|.|/"]
              .map!(r => r.split("|")).array;

enum straddle = (in string s) pure /*nothrow @safe*/ =>
    toUpper(s)
    .split("")
    .cartesianProduct(T)
    .filter!(cL => cL[1].canFind(cL[0]))
    .map!(cL => cL[1][0] ~ T[0][cL[1].countUntil(cL[0])])
    .join;

string unStraddle(string s) pure nothrow @safe {
    string result;
    for (; !s.empty; s.popFront) {
        immutable i = [T[2][0], T[3][0]].countUntil([s[0]]);
        if (i >= 0) {
            s.popFront;
            immutable n = T[2 + i][T[0].countUntil([s[0]])];
            if (n == "/") {
                s.popFront;
                result ~= s[0];
            } else result ~= n;
        } else
            result ~= T[1][T[0].countUntil([s[0]])];
    }
    return result;
}

void main() {
    immutable O = "One night-it was on the twentieth of March, 1888-I was returning";
    writeln("Encoded: ", O.straddle);
    writeln("Decoded: ", O.straddle.unStraddle);
}

{{out}}

Encoded: 139539363509369743061399059745399365901344308320791798798798367430685972839363935
Decoded: ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING

Alternative Version

{{trans|C++}} Same output:

import std.stdio, std.algorithm, std.ascii;

struct StraddlingCheckerboard {
  private:
    string[char] table;
    char[10] first, second, third;
    const int rowU, rowV;

  public:
    this(in string alphabet, in int u, in int v) pure nothrow {
        rowU = min(u, v);
        rowV = max(u, v);

        int j = 0;
        foreach (immutable i; 0 .. 10) {
            if (i != u && i != v) {
                first[i] = alphabet[j];
                table[alphabet[j]] = digits[i .. i + 1];
                j++;
            }

            second[i] = alphabet[i + 8];
            table[alphabet[i + 8]] = [digits[rowU], digits[i]];

            third[i] = alphabet[i + 18];
            table[alphabet[i + 18]] = [digits[rowV], digits[i]];
        }
    }

    string encode(in string plain) const pure nothrow {
        string r;
        foreach (immutable char c; plain) {
            if      (c.isLower) r ~= table[c.toUpper];
            else if (c.isUpper) r ~= table[c];
            else if (c.isDigit) r ~= table['/'] ~ c;
        }
        return r;
    }

    string decode(in string cipher) const pure nothrow {
        string r;
        int state = 0;

        foreach (immutable char c; cipher) {
            immutable int n = c - '0';
            char next = '\0';

            if (state == 1)      next = second[n];
            else if (state == 2) next = third[n];
            else if (state == 3) next = c;
            else if (n == rowU)  state = 1;
            else if (n == rowV)  state = 2;
            else                 next = first[n];

            if (next == '/')
                state = 3;
            else if (next != 0) {
                state = 0;
                r ~= next;
            }
        }
        return r;
    }
}

void main() {
    immutable orig =
    "One night-it was on the twentieth of March, 1888-I was returning";
    writeln("Original: ", orig);
    const sc = StraddlingCheckerboard("HOLMESRTABCDFGIJKNPQUVWXYZ./",
                                      3, 7);
    const en = sc.encode(orig);
    writeln("Encoded:  ", en);
    writeln("Decoded:  ", sc.decode(en));
}

===Dictionary-Based Version=== {{trans|Java}}

import std.stdio, std.string, std.algorithm, std.regex, std.array, std.range, std.typecons;

immutable string[const string] val2key, key2val;

static this() pure /*nothrow @safe*/ {
    immutable aa = ["A":"30", "B":"31", "C":"32", "D":"33", "E":"5", "F":"34", "G":"35",
        "H":"0", "I":"36", "J":"37", "K":"38", "L":"2", "M":"4", ".":"78", "N":"39",
        "/":"79", "O":"1", "0":"790", "P":"70", "1":"791", "Q":"71", "2":"792",
        "R":"8", "3":"793", "S":"6", "4":"794", "T":"9", "5":"795", "U":"72",
        "6":"796", "V":"73", "7":"797", "W":"74", "8":"798", "X":"75", "9":"799",
        "Y":"76", "Z":"77"];
    val2key = aa;
    key2val = aa.byKeyValue.map!(t => tuple(t.value, t.key)).assocArray;
}

string encode(in string s) pure /*nothrow*/ @safe {
    return s.toUpper.split("").map!(c => val2key.get(c, "")).join;
}

string decode(in string s) /*pure nothrow*/ @safe {
    return s.matchAll("79.|3.|7.|.").map!(g => key2val.get(g[0], "")).join;
}

void main() @safe {
    immutable s = "One night-it was on the twentieth of March, 1888-I was returning";
    s.encode.writeln;
    s.encode.decode.writeln;
}

{{out}}

139539363509369743061399059745399365901344308320791798798798367430685972839363935
ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING

=={{header|F_Sharp|F#}}==


(*
Encode and Decode using StraddlingCheckerboard
Nigel Galloway May 15th., 2017
*)
type G={n:char;i:char;g:System.Collections.Generic.Dictionary<(char*char),string>;e:System.Collections.Generic.Dictionary<char,string>}
       member G.encode n=n|>Seq.map(fun n->if (n='/') then G.e.['/']+string n else match (G.e.TryGetValue(n)) with |(true,n)->n|(false,_)->G.e.['/']+string n)
       member G.decode n =
         let rec fn n = seq{ if not (Seq.isEmpty n)
           then match (match Seq.head n with |g when g=G.n||g=G.i->(G.g.[(g,(Seq.item 1 n))],(Seq.skip 2 n))|g->(G.g.[('/',g)],(Seq.tail n))) with
                |(a,b) when a="/"->yield string (Seq.head b); yield! fn (Seq.tail b)
                |(a,b)           ->yield a;                   yield! fn b
         }
         fn n
let G n i g e l z=
  let a = new System.Collections.Generic.Dictionary<(char*char),string>()
  let b = new System.Collections.Generic.Dictionary<char,string>()
  Seq.iter2 (fun ng gn->a.[('/'   ,char ng)]<-string gn;b.[gn]<-ng) (List.except [n;i] z) g
  Seq.iter2 (fun ng gn->a.[(char n,char ng)]<-string gn;b.[gn]<-n+ng)                  z  e
  Seq.iter2 (fun ng gn->a.[(char i,char ng)]<-string gn;b.[gn]<-i+ng)                  z  l
  {n=char n;i=char i;g=a;e=b}

{{out}} {{out}}


let N = G "2" "6" "ETAONRIS" "BCDFGHJKLM" "PQ/UVWXYZ." ["0";"1";"2";"3";"4";"5";"6";"7";"8";"9"]
N.decode "450582425181653945125016505180125423293721256216286286288653970163758524"|>Seq.iter(fun n->printf "%s" n);; //ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING
N.encode "IN THE WINTER 1965 WE WERE HUNGRY JUST BARELY ALIVE"|>Seq.iter(fun n->printfn "%s" n);; //8562 125062 658510762 62162962662562 65062 6507062 256352476762 26639162 20370286762 3288640
N.decode "8562 125062 658510762 62162962662562 65062 6507062 256352476762 26639162 20370286762 3288640"|>Seq.iter(fun n->printf "%s" n);; //IN THE WINTER 1965 WE WERE HUNGRY JUST BARELY ALIVE

Go

package main

import (
    "fmt"
    "strings"
)

func main() {
    key := `
 8752390146
 ET AON RIS
5BC/FGHJKLM
0PQD.VWXYZU`
    p := "you have put on 7.5 pounds since I saw you."
    fmt.Println(p)
    c := enc(key, p)
    fmt.Println(c)
    fmt.Println(dec(key, c))
}

func enc(bd, pt string) (ct string) {
    enc := make(map[byte]string)
    row := strings.Split(bd, "\n")[1:]
    r2d := row[2][:1]
    r3d := row[3][:1]
    for col := 1; col <= 10; col++ {
        d := string(row[0][col])
        enc[row[1][col]] = d
        enc[row[2][col]] = r2d+d
        enc[row[3][col]] = r3d+d
    }
    num := enc['/']
    delete(enc, '/')
    delete(enc, ' ')
    for i := 0; i < len(pt); i++ {
        if c := pt[i]; c <= '9' && c >= '0' {
            ct += num + string(c)
        } else {
            if c <= 'z' && c >= 'a' {
                c -= 'a'-'A'
            }
            ct += enc[c]
        }
    }
    return
}

func dec(bd, ct string) (pt string) {
    row := strings.Split(bd, "\n")[1:]
    var cx [10]int
    for i := 1; i <= 10; i++ {
        cx[row[0][i]-'0'] = i
    }
    r2d := row[2][0]-'0'
    r3d := row[3][0]-'0'
    for i := 0; i < len(ct); i++ {
        var r int
        switch d := ct[i]-'0'; d {
        case r2d:
            r = 2
        case r3d:
            r = 3
        default:
            pt += string(row[1][cx[d]])
            continue
        }
        i++
        if b := row[r][cx[ct[i]-'0']]; b == '/' {
            i++
            pt += string(ct[i])
        } else {
            pt += string(b)
        }
    }
    return
}

{{out}}


you have put on 7.5 pounds since I saw you.
01306592038080673955702555083069056649578462090130602
YOUHAVEPUTON7.5POUNDSSINCEISAWYOU.

Haskell

import Data.Char
import Data.Map

charToInt :: Char -> Int
charToInt c = ord c - ord '0'

-- Given a string, decode a single character from the string.
-- Return the decoded char and the remaining undecoded string.
decodeChar :: String -> (Char,String)
decodeChar ('7':'9':r:rs) = (r,rs)
decodeChar ('7':r:rs)     = ("PQUVWXYZ. " !! charToInt r, rs)
decodeChar ('3':r:rs)     = ("ABCDFGIJKN" !! charToInt r, rs)
decodeChar (r:rs)         = ("HOL MES RT" !! charToInt r, rs)

-- Decode an entire string.
decode :: String -> String
decode [] = []
decode st = let (c, s) = decodeChar st in c:decode s

-- Given a string, decode a single character from the string.
-- Return the decoded char and the part of the encoded string
-- used to encode that character.
revEnc :: String -> (Char, String)
revEnc enc = let (dec, rm) = decodeChar enc in (dec, take (length enc - length rm) enc)

ds :: String
ds = ['0'..'9']

-- Decode all 1000 possible encodings of three digits and
-- use results to construct map used to encode.
encodeMap :: Map Char String
encodeMap = fromList [ revEnc [d2,d1,d0] | d2 <- ds, d1 <- ds, d0 <- ds ]

-- Encode a single char using encoding map.
encodeChar :: Char -> String
encodeChar c = findWithDefault "" c encodeMap

-- Encode an entire string.
encode :: String -> String
encode st = concatMap encodeChar $ fmap toUpper st

-- Test by encoding, decoding, printing results.
main = let orig = "One night-it was on the twentieth of March, 1888-I was returning"
           enc = encode orig
           dec = decode enc
       in mapM_ putStrLn [ "Original: " ++ orig
                         , "Encoded: " ++ enc
                         , "Decoded: " ++ dec ]

{{out}}

Original: One night-it was on the twentieth of March, 1888-I was returning
Encoded: 139539363509369743061399059745399365901344308320791798798798367430685972839363935
Decoded: ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING

```

=={{header|Icon}} and {{header|Unicon}}==

```Icon
procedure main()
StraddlingCheckerBoard("setup","HOLMESRTABCDFGIJKNPQUVWXYZ./", 3,7)

text := "One night. it was on the twentieth of March, 1888. I was returning"
write("text   = ",image(text))
write("encode = ",image(en := StraddlingCheckerBoard("encode",text)))
write("decode = ",image(StraddlingCheckerBoard("decode",en)))
end

procedure StraddlingCheckerBoard(act,text,b1,b2)
static SCE,SCD
case act of {
   "setup" : {
      if (b1 < b2 < 10) & (*text = *cset(text) = 28) then {
         SCE := table("")
         SCD := table()
         esc := text[-1]                               # escape
         every text[(b1|b2)+1+:0] := " "               # blanks
         uix := ["",b1,b2]                             # 1st position
         every c := text[1 + (i := 0 to *text-1)] do   # build translation
            if c ~== " " then                          # skip blanks
               SCD[SCE[c] := SCE[map(c)] := uix[i/10+1]||(i%10) ] := c
         every c := !&digits do
            SCD[SCE[c] := SCE[esc] || c] := c
         delete(SCD,SCE[esc])
         delete(SCE,esc)
         }
         else stop("Improper setup: ",image(text),", ",b1,", ",b2)
      }
   "encode" : {
      every (s := "") ||:= x := SCE[c := !text]
      return s
      }
   "decode" : {
      s := ""
      text ? until pos(0) do
         s ||:= \SCD[k := move(1 to 3)]
      return s
      }
   }
end
```


Output:
```txt
text   = "One night. it was on the twentieth of March, 1888. I was returning"
encode = "1395393635097836974306139905974539936590134430832079179879879878367430685972839363935"
decode = "ONENIGHT.ITWASONTHETWENTIETHOFMARCH1888.IWASRETURNING"
```



## J

'''Solution:'''

```j
'Esc Stop'=: '/.'
'Nums Alpha'=: '0123456789';'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Charset=: Nums,Alpha,Stop

escapenum=: (,@:((; Esc&,)&>) Nums) rplc~ ]               NB. escape numbers
unescapenum=: ((, ; ' '&,@])"1 0  Nums"_) rplc~ ]         NB. unescape coded numbers (x is escape code, y is cipher)
expandKeyatUV=: 0:`[`(1 #~ 2 + #@])} #inv ]
makeChkBrd=: Nums , expandKeyatUV

chkbrd=: conjunction define
  'uv key'=. n
  board=. uv makeChkBrd key
  select. m
  case. 0 do.                                                      NB. encode
    digits=. board 10&#.inv@i. escapenum y
    ' ' -.~ ,(":@{:"1 digits) ,.~ (1 1 0 2{":uv) {~ {."1 digits
  case. 1 do.                                                      NB. decode
    esc=. 0 chkbrd (uv;key) Esc                                    NB. find code for Esc char
    tmp=. esc unescapenum esc,'0',y
    tmp=. ((":uv) ((-.@e.~ _1&|.) *. e.~) tmp) <;.1 tmp            NB. box on chars from rows 0 2 3
    idx=. (}. ,~ (1 1 0 2{":uv) ":@i. {.) each tmp                 NB. recreate indices for rows 0 2 3
    idx=. ;(2&{. , [: ((0 1 $~ +:@#) #inv!.'1' ]) 2&}.) each idx   NB. recreate indices for row 1
    }.board {~ _2 (_&".)\ idx
  end.
)
```

'''Example usage:'''

```j
   preprocess=: (#~ Charset e.~ ])@toupper                 NB. verb to compress out non-alphanumerics
   chkbrdRC=: chkbrd (3 7;'HOLMESRTABCDFGIJKNPQUVWXYZ./')  NB. define adverb by applying Rosetta Code key to chkbrd conjunction
   0 chkbrdRC preprocess 'One night-it was on the twentieth of March, 1888-I was returning'
139539363509369743061399059745399365901344308320791798798798367430685972839363935
   1 chkbrdRC 0 chkbrdRC preprocess 'One night-it was on the twentieth of March, 1888-I was returning'
ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING
```

Or using the rules proposed by [[User:Util|Util]] on the discussion page:

```j
   preprocess=: Stop&([`([: I. Charset -.@e.~ ])`]} toupper) NB. replace all non-alphanumerics with Stop
   1 chkbrdRC 0 chkbrdRC preprocess 'One night-it was on the twentieth of March, 1888-I was returning'
ONE.NIGHT.IT.WAS.ON.THE.TWENTIETH.OF.MARCH..1888.I.WAS.RETURNING
```



Another method is to create a set of keys which correspond to the encoded letters in the alphabet. This allows for the relatively simple design of the encoding and decoding functions as they are essentially hash table lookups.

'''Solution:'''

```j
NB. stops setcode alphabet
NB. creates verbs encode and decode which change between unencoded text and lists of encoded numbers
   setcode=: 3 :0
2 6 setcode y
:
alphabet=: y, ,":"0 i.10
stops=. x
alphkeys=. (a: , ,&.> x) ([ -.~ [: , ,&.>/) i.10
esckey=. >(alphabet i. '/'){alphkeys
numkeys=. esckey&,&.> i.10
keys=. alphkeys,numkeys

encode=: ([: ; keys {~ alphabet&i.) :. decode
break=. /\.&.|. e.&stops) + _1|.2*esckey&E.
decode=: (alphabet {~ keys i. break f.) :. encode
i.0 0
)
```


'''Example usage:'''

```j
   3 7 setcode 'HOLMESRTABCDFGIJKNPQUVWXYZ./'
   preprocess=: (#~ alphabet e.~ ])@toupper
   ,":"0 encode message=: preprocess 'One night-it was on the twentieth of March, 1888-I was returning'
139539363509369743061399059745399365901344308320791798798798367430685972839363935
   decode encode message
ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING
   ]s=. ((10|+) 0 4 5 2$~$)&.encode message NB. scramble by taking a modular sum with 0 4 5 2 while encoded
OWVKRNEOAMTMXROWOHTMTMTROTQ4SEMRRLRZLVSTTLLOROMHALSFOHECMRWESWEE
   ((10|-) 0 4 5 2$~$)&.encode s
ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING
```



## Java

{{works with|Java|7}}

```java
import java.util.HashMap;
import java.util.Map;
import java.util.regex.*;

public class StraddlingCheckerboard {

    final static String[] keyvals = {"H:0", "O:1", "L:2", "M:4", "E:5", "S:6",
        "R:8", "T:9", "A:30", "B:31", "C:32", "D:33", "F:34", "G:35", "I:36",
        "J:37", "K:38", "N:39", "P:70", "Q:71", "U:72", "V:73", "W:74", "X:75",
        "Y:76", "Z:77", ".:78", "/:79", "0:790", "1:791", "2:792", "3:793",
        "4:794", "5:795", "6:796", "7:797", "8:798", "9:799"};

    final static Map val2key = new HashMap<>();
    final static Map key2val = new HashMap<>();

    public static void main(String[] args) {
        for (String keyval : keyvals) {
            String[] kv = keyval.split(":");
            val2key.put(kv[0], kv[1]);
            key2val.put(kv[1], kv[0]);
        }
        String enc = encode("One night-it was on the twentieth of March, "
                + "1888-I was returning");
        System.out.println(enc);
        System.out.println(decode(enc));
    }

    static String encode(String s) {
        StringBuilder sb = new StringBuilder();
        for (String c : s.toUpperCase().split("")) {
            c = val2key.get(c);
            if (c != null)
                sb.append(c);
        }
        return sb.toString();
    }

    static String decode(String s) {
        Matcher m = Pattern.compile("(79.|3.|7.|.)").matcher(s);
        StringBuilder sb = new StringBuilder();
        while (m.find()) {
            String v = key2val.get(m.group(1));
            if (v != null)
                sb.append(v);
        }
        return sb.toString();
    }
}
```



```txt
139539363509369743061399059745399365901344308320791798798798367430685972839363935
ONENIGHTITWASONTHETWENTIETHOFMARCH1888IWASRETURNING
```



## JavaScript


```javascript>