On the algorithm: I convert to my 5 bit character set, build a huge number from that effectively base 32, decode it as a base 840 number, and use those "digits" to pick the layout and ordering on each row. Decoding just reverses the process.
On the algorithm: I convert to my 5 bit character set, build a huge number from that effectively base 32, decode it as a base 840 number, and use those "digits" to pick the layout and ordering on each row. Decoding just reverses the process.
Before beginning, I would like to distinguish between a code and a cipher. A code may be a means of placing a value of one sort into something of another. For instance, ASCII codes the letter A as seven bits 0010001. Alternatively, a code may be a replacement of certain texts by other texts, like a military "codebook". A cipher, on the other hand, is a means of changing one arbitrary text into another text, using cryptography. The "Details" talks ciphers, but "The challenge" is most definitely a code.
Having said all that, I consider what I've produced a code, though the "perturb"ing of the lists in common.h could be considered a 361.28... bit cipher key. To be usable as a cipher, that perturbation would need to be configurable. And note that some plaintexts (samples below) give away information, so it isn't the best cipher.
The game is replacement chess, without promotion. That is to say, a chessboard with all 32 pieces on it, in any position. Further, check is irrelevant in the position (and I have produced cases with adjacent kings).
I have chosen to use a 5-bit reduced character set: space, (uppercase) letters, period, comma, question mark, exclamation point, and asterisk (which is also my "replacement character"). This allows me to encode 15 characters into the chess board. (Using ASCII would allow 11, ISO8859-1 would allow 9.)
I have also restricted the positions that pieces may be in. Each row must have two pawns, one white non-pawn, and one black non-pawn. I don't care which non-pawn is used, and my encoder randomly selects. Similarly, the color of the pawns doesn't matter, and is randomly chosen. This gives 840^8 (about 2.4E23) possible significant positions. (Complete arbitrary placement would yield 64!/32!/8!/8!/64 or about 4.6E42 positions, would make the coding a more difficult problem, and would allow encoding 28 characters.)
I have separate C programs for encoding and decoding, and a common header file. My encode program pads the input text with spaces. My decode program outputs the text with the trailing spaces. My programs output and input the chessboard in the form given in this answer. The decoder is fairly permissive on its input, but if you reduce the spaces, a blank square must become an underscore.
File encode.c (Encodes its only command line parameter into a chessboard.)
#include "common.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
unsigned translate[256];
void init_translate(void)
{
// build a table to reverse the "charset" variable
for (int i=0; i<256; i++) translate[i] = 31;
for (int i=0; charset[i]; i++) {
unsigned char ch = charset[i];
translate[ch] = i;
if ((ch >= 'A') && (ch <= 'Z')) translate[ch | 0x20] = i;
}
}
void init(void)
{
init_translate();
srand48(time(0));
}
char pick(char data[32])
{
//select, without replacement, a piece to output from a list
int l = strlen(data);
if (l == 0) return '?';
int pick = lrand48() % l;
char ret = data[pick];
data[pick] = data[l-1];
data[l-1] = 0;
return ret;
}
void encode(char const *raw_message)
{
BIG nummsg = 0;
{
// first stage: translate the characters to 0 to 31, and combine
// them into a single large integer
int i;
for (i=0; i<MAXCHAR; i++) {
unsigned char ch = raw_message[i];
if (ch)
nummsg = nummsg * 32 + translate[ch];
else
break;
}
// messages can be too big -- an error
if (raw_message[i]) {
fprintf(stderr,"Message \"%s\" too long (limit %d)\n", raw_message, MAXCHAR);
return;
}
// messages can be too small -- pad
for (; i<MAXCHAR; i++) nummsg = nummsg * 32 + translate[' '];
}
// nummsg must be <247875891108249600000000
DEBUG(print_nummsg;)
// these are overly long, and specifically arrays
// they get modified by pick()
char available_B[32] = "kqrrbbnn";
char available_W[32] = "KQRRBBNN";
char available_P[32] = "PPPPPPPPpppppppp";
// calculate positions and output
#define LETTERS " A B C D E F G H\n"
#define BOUNDARY " |-----|-----|-----|-----|-----|-----|-----|-----|\n"
printf(LETTERS BOUNDARY);
for (int i=0; i<8; i++) {
// rownum is the value for one row 0<=rownum<840
int rownum = nummsg % (LAYOUTS*ORDERINGS);
nummsg /= LAYOUTS*ORDERINGS;
// lay and ord are the indexs into the common arrays for this row
int lay = rownum % LAYOUTS;
int ord = rownum / LAYOUTS;
DEBUG(printf("(%2d,%2d) ", ord, lay);)
//ordering and layout are the specific values being used.
//'x' in layout becomes a piece type from ordering which
//pick() turns into a piece.
char const *ordering = orderings[ord];
printf("%d |", 8-i);
for (char const *layout = layouts[lay]; *layout; layout++) {
if (*layout == 'x') {
char o = *ordering++;
DEBUG(printf("%c", o);)
char ch = o;
switch(o) {
case 'B': ch = pick(available_B); break;
case 'W': ch = pick(available_W); break;
case 'P': ch = pick(available_P); break;
}
printf(" %c |", ch);
} else {
printf(" |");
}
}
printf(" %d\n" BOUNDARY, 8-i);
}
printf(LETTERS);
if (nummsg != 0) printf("Leftover data!\n");
}
int main(int argc, char **argv)
{
init();
if (argc > 1) {
for (int i=1; i<argc; i++)
encode(argv[i]);
return 0;
} else {
fprintf(stderr, "Usage: encode <message>...\n");
return 1;
}
}
File decode.c (Decodes a chessboard on standard input to a plaintext message.)
#include "common.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
BIG nummsg = 0;
BIG mul = 1;
// first stage is to decode the rows
for (int done=0;done<8;) {
char line[256];
if (!fgets(line, sizeof(line), stdin)) break;
// header lines don't count
if (strchr(line, 'A')) continue;
// only some spaces count. make them '_'
{ char *p; while (p = strstr(line, "| ")) p[3] = '_'; }
// from: "8 | _ | n | P | _ | _ | p | R | _ | 8\n"
// extract the letters to, _BP__PW_
// but then go farther, to layout="_xx__xx_" and ordering="BPPW"
char layout[256];
char ordering[256];
{
char *l = layout;
char *o = ordering;
for (char const *in=line; *in; in++) {
char ch = *in;
if ((ch == 'p') || (ch == 'P')) { *l++ = 'x'; *o++ = 'P'; }
else if ((ch >= 'a') && (ch <= 'z')) { *l++ = 'x'; *o++ = 'B'; }
else if ((ch >= 'A') && (ch <= 'Z')) { *l++ = 'x'; *o++ = 'W'; }
else if (ch == '_') { *l++ = '_'; }
}
if (l == layout) continue;
*l = 0;
*o = 0;
}
DEBUG(printf("%s %s\n", layout, ordering);)
// Find the numbers for these strings
int lay, ord;
for (lay=0; lay<LAYOUTS; lay++) if (!strcmp(layout,layouts[lay])) break;
for (ord=0; ord<ORDERINGS; ord++) if (!strcmp(ordering,orderings[ord])) break;
if ((lay==LAYOUTS) || (ord==ORDERINGS)) {
fprintf(stderr,"Bad line: %s", line);
exit(1);
}
DEBUG(printf("%d %d\n", ord, lay);)
// Combine these into the large encoded board number
// I have to do these backwards
nummsg += mul * (ord * LAYOUTS + lay);
mul *= ORDERINGS*LAYOUTS;
done++;
}
DEBUG(print_nummsg;)
{
// change the board number into a string of characters, and output
// again I have to do this backwards
char output[MAXCHAR+1];
char *o = output+sizeof(output);
*--o = 0;
while (o > output) {
int ch = nummsg % 32;
nummsg /= 32;
*--o = charset[ch];
}
printf("%s\n", output);
}
}
File common.h (Common data and declarations for both sources.)
#ifndef COMMON_H_INCLUDED
#define COMMON_H_INCLUDED
typedef __int128 BIG;
#define DEBUG(x) //x
#define XDEBUG(x) x
enum { MAXCHAR = 15 };
unsigned char const charset[32+1] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ.,!?*";
#define print_nummsg fprintf(stderr, "%016llx%016llx\n", (long long)(nummsg>>64), (long long)(nummsg))
// Possible ordering of pieces on a row. This list has be run through
// shuf(1), just to perturb it. W is white non-pawn. B is black
// non-pawn. P is any pawn. I decided I did't need another 8 bits
// from distinguishing the pawns. Or what I would get from allowing
// any piece anywhere.
enum {ORDERINGS = 12};
char const *orderings[ORDERINGS] = {
"WPPB", "PBWP", "PPWB", "WBPP", "BPWP", "WPBP",
"BPPW", "PBPW", "PPBW", "PWPB", "BWPP", "PWBP",
};
// Possible layouts of pieces on a row. This list has be run through
// shuf(1), just to perturb it.
enum {LAYOUTS = 70};
char const *layouts[LAYOUTS] = {
"x_xx___x", "x___xxx_", "x__x_xx_", "xxxx____", "x_x__x_x",
"_xxx___x", "xx_xx___", "xx____xx", "x__x_x_x", "x___xx_x",
"xx_x_x__", "_xxx__x_", "_x_xx__x", "x____xxx", "x_x_xx__",
"__x_xx_x", "xxx__x__", "_x__xxx_", "x_xx_x__", "x_xxx___",
"_xx__xx_", "x__xxx__", "_x_xx_x_", "_xx_x_x_", "xxx___x_",
"x__xx__x", "x_xx__x_", "x_x__xx_", "_x__x_xx", "_xxxx___",
"_xxx_x__", "__xx__xx", "xxx____x", "__x_xxx_", "__xxx_x_",
"xxx_x___", "___xx_xx", "__xxx__x", "___x_xxx", "__x__xxx",
"xx___x_x", "x__xx_x_", "xx__xx__", "___xxxx_", "_x_xxx__",
"_x__xx_x", "_x___xxx", "xx___xx_", "__xx_x_x", "x_x_x_x_",
"_x_x_xx_", "_x_x_x_x", "xx_x__x_", "xx__x_x_", "_xx__x_x",
"__xxxx__", "__xx_xx_", "x__x__xx", "xx__x__x", "___xxx_x",
"xx_x___x", "x_x___xx", "_xx_x__x", "_x_x__xx", "__x_x_xx",
"_xx___xx", "____xxxx", "x_x_x__x", "x___x_xx", "_xx_xx__",
};
#endif
The presented sample data:
$ ./encode 'TREASURE'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | | n | p | | | P | N | | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | | r | | | Q | p | | p | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | p | | R | | P | | r | | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | P | | P | K | | | b | | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | | p | | b | | N | P | | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | | | | B | P | P | q | | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | | R | k | p | | p | | | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | | p | | n | B | | | P | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode 'TREASURE' | ./decode
TREASURE
$ ./encode 'LOOKLEFT'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | B | | P | P | | | | n | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | P | | | p | | b | | B | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | | p | P | | Q | q | | | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | | p | k | p | | R | | | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | | r | p | P | | | R | | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | | | r | P | | p | N | | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | | P | N | | b | | p | | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | K | | p | | P | | n | | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode 'LOOKLEFT' | ./decode
LOOKLEFT
$ ./encode 'SECRETED'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | | B | n | p | | P | | | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | p | | P | n | | | Q | | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | N | | | p | | | P | b | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | B | | | P | p | k | | | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | P | | | r | R | | p | | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | | K | | q | p | | | P | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | | | | p | r | P | | R | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | p | b | | N | P | | | | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode 'SECRETED' | ./decode
SECRETED
$ ./encode 'DIGHERE!'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | | r | | | R | | P | p | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | | k | | | K | P | p | | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | | P | N | | | p | b | | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | p | | P | | | | N | b | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | | P | r | p | | B | | | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | | p | | | q | | p | Q | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | P | | n | | | | R | p | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | | B | | | P | P | n | | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode 'DIGHERE!' | ./decode
DIGHERE!
$ ./encode 'TOMORROW'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | Q | p | | | | p | | k | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | | R | p | P | | | b | | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | P | | | N | | | P | n | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | p | | b | | | N | | P | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | | p | | K | | r | p | | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | P | | | P | | n | | B | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | | p | | R | q | | P | | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | | P | r | B | | | p | | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode 'TOMORROW' | ./decode
TOMORROW
$
Some other examples:
$ ./encode 'More Treasures!'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | N | P | | | | k | p | | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | K | | b | | | P | | P | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | | | | R | P | p | | n | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | B | P | r | | | | | P | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | Q | p | | | r | | | P | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | | q | p | | R | p | | | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | | | p | | B | n | p | | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | N | p | | | P | | b | | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode 'More Treasures!' | ./decode
MORE TREASURES!
$ ./encode 'Secret Message.'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | n | | p | | | R | p | | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | | | R | b | P | P | | | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | p | k | | P | N | | | | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | p | | q | | | p | K | | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | | P | b | B | | P | | | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | | N | | r | p | | | P | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | | | | P | r | P | | B | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | p | n | | Q | p | | | | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode 'Secret Message.' | ./decode
SECRET MESSAGE.
$ ./encode '(yes) 123'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | | p | | | p | | B | q | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | | | P | | p | Q | | k | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | P | | P | | | n | R | | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | P | K | n | | | | | P | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | r | P | | | P | | | N | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | | B | r | P | | p | | | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | p | | p | | | R | | b | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | p | | | b | | | N | p | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode '(yes) 123' | ./decode
*YES* ***
$ ./encode ''
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | R | | P | p | | | | r | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | N | | P | P | | | | b | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | N | | p | p | | | | k | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | B | | P | P | | | | q | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | K | | P | p | | | | n | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | Q | | P | p | | | | r | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | R | | p | P | | | | n | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | B | | p | p | | | | b | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode '' | ./decode
$ ./encode ' A'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | Q | | | | P | P | r | | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | K | | p | p | | | | b | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | N | | p | P | | | | r | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | R | | p | P | | | | k | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | B | | p | p | | | | n | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | N | | P | p | | | | b | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | B | | p | P | | | | n | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | R | | P | P | | | | q | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode ' A' | ./decode
A
$ ./encode 'A'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | | P | | P | B | r | | | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | p | | | p | n | | Q | | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | | p | P | | r | N | | | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | | p | P | k | R | | | | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | | q | | | p | p | R | | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | P | n | | P | | | | B | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | K | | P | p | | | | b | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | N | | P | | | p | | b | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./encode 'A' | ./decode
A
$ ./encode 'This text is too long.'
Message "This text is too long." too long (limit 15)
$
The result of shuffling the lines in an encoding of TREASURE
$ cat 'shuffle.txt'
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
6 | p | | K | | P | | k | | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
|-----|-----|-----|-----|-----|-----|-----|-----|
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
3 | | | | N | p | p | b | | 3
4 | | p | | b | | B | p | | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | | N | r | P | | P | | | 2
5 | p | | P | Q | | | r | | 5
7 | | q | | | R | p | | p | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | | n | P | | | P | R | | 8
1 | | P | | n | B | | | P | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
$ ./decode <shuffle.txt
TTBG.PPP?SB,SM*
$
The result of rotating the board 180 degrees from an encoding of TREASURE
$ cat 'reversed.txt'
A B C D E F G H
|-----|-----|-----|-----|-----|-----|-----|-----|
8 | P | | | N | n | | P | | 8
|-----|-----|-----|-----|-----|-----|-----|-----|
7 | | | p | | p | b | R | | 7
|-----|-----|-----|-----|-----|-----|-----|-----|
6 | | r | p | P | Q | | | | 6
|-----|-----|-----|-----|-----|-----|-----|-----|
5 | | p | R | | q | | p | | 5
|-----|-----|-----|-----|-----|-----|-----|-----|
4 | | b | | | B | p | | p | 4
|-----|-----|-----|-----|-----|-----|-----|-----|
3 | | n | | P | | K | | p | 3
|-----|-----|-----|-----|-----|-----|-----|-----|
2 | P | | P | N | | | r | | 2
|-----|-----|-----|-----|-----|-----|-----|-----|
1 | | B | P | | | P | k | | 1
|-----|-----|-----|-----|-----|-----|-----|-----|
A B C D E F G H
$ ./decode <reversed.txt
EAQVOLBEE PY YS
$
The result of minimally reducing the board of an encoding of TREASURE
$ cat 'reduced.txt'
_rP__pB_
_r__RP_p
p_N_P_b_
P_pN__n_
_p_q_Kp_
___QpPn_
_RbP_P__
_p_kB__P
$ ./decode <reduced.txt
TREASURE
$
(Now I want to go setup a message in my local library.)