/* Find fixpoints and cycles in base64 -- Antoine Amarilli, 2013
* Usage: ./a.out for standard base64
* ./a.out TABLE for custom encoding (must have strlen(table) == 64) */
#include <stdio.h>
#include <assert.h>
#include <string.h>
// The base64 table
char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* Will contain:
* -1 if uninitialized
* <-1 if being currently explored
* >0 is distance to a stable configuration (a fixpoint or a cycle member) */
int graph[256][256][256];
int explore(unsigned char i, unsigned char j, unsigned char k, int d) {
/* encode ijk until reaching a fixpoint or cycle,
* return distance to a stable configuration
* (or <0 if within stable configuration),
* d is the current distance travelled */
if (graph[i][j][k] >= 0) {
// we know how to reach fixpoint from here in that many hops
return graph[i][j][k];
}
if (graph[i][j][k] < -1) {
// we hit something in the current stack
// retrieve the cycle length from the current d and store value
int period = d + graph[i][j][k] + 1;
printf("Stable configuration of period %d: %c%c%c alias %d %d %d\n", period, i, j, k, i, j, k);
// unwind the stack: return the negative length of the cycle so that all
// cycle members are set to zero
return -period-1;
}
// mark that we are exploring this node and the distance traveled
graph[i][j][k] = -2 - d;
unsigned char u,v,w;
u = (i&~0x03)>>2;
v = (i&0x03)<<4 | (j&~0x0F)>>4;
w = (j&0x0F)<<2 | (k&~0x3F)>>6;
int ret = explore(b64[u], b64[v], b64[w], d+1);
if (ret >= 0) {
// our distance to stable is one plus distance to stable of our image
graph[i][j][k] = ret+1;
} else {
// we are unwinding a stable configuration
graph[i][j][k] = 0;
}
// return our distance to stable, or continue unwinding
return ret+1;
}
int main(int argc, char **argv) {
int i, j, k;
// initialization
for (i=0; i<256; i++)
for (j=0; j<256; j++)
for (k=0; k<256; k++)
graph[i][j][k] = -1;
if (argc == 2) {
// a custom table has been passed
b64 = argv[1];
}
int max = 0;
int ret;
unsigned char va=0, vb=0, vc=0;
for (i=0; i<256; i++)
for (j=0; j<256; j++)
for (k=0; k<256; k++) {
ret = explore(i, j, k, 0);
if (ret > max) {
max = ret;
va = i; vb = j; vc = k;
}
}
// print which is the longest way to reach a stable configuration
printf("Longest chain is from %d %d %d (%d hops)\n", va
, vb
, vc
, max
); return 0;
}
LyogRmluZCBmaXhwb2ludHMgYW5kIGN5Y2xlcyBpbiBiYXNlNjQgLS0gQW50b2luZSBBbWFyaWxsaSwgMjAxMwogKiBVc2FnZTogLi9hLm91dCBmb3Igc3RhbmRhcmQgYmFzZTY0IAogKiAgICAgICAgLi9hLm91dCBUQUJMRSBmb3IgY3VzdG9tIGVuY29kaW5nIChtdXN0IGhhdmUgc3RybGVuKHRhYmxlKSA9PSA2NCkgKi8gCgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPGFzc2VydC5oPgojaW5jbHVkZSA8c3RyaW5nLmg+CgovLyBUaGUgYmFzZTY0IHRhYmxlCmNoYXIgKmI2NCA9ICJBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvIjsKCi8qIFdpbGwgY29udGFpbjoKICogLTEgaWYgdW5pbml0aWFsaXplZAogKiA8LTEgaWYgYmVpbmcgY3VycmVudGx5IGV4cGxvcmVkCiAqID4wIGlzIGRpc3RhbmNlIHRvIGEgc3RhYmxlIGNvbmZpZ3VyYXRpb24gKGEgZml4cG9pbnQgb3IgYSBjeWNsZSBtZW1iZXIpICovCmludCBncmFwaFsyNTZdWzI1Nl1bMjU2XTsKCmludCBleHBsb3JlKHVuc2lnbmVkIGNoYXIgaSwgdW5zaWduZWQgY2hhciBqLCB1bnNpZ25lZCBjaGFyIGssIGludCBkKSB7CiAgLyogZW5jb2RlIGlqayB1bnRpbCByZWFjaGluZyBhIGZpeHBvaW50IG9yIGN5Y2xlLAogICAqIHJldHVybiBkaXN0YW5jZSB0byBhIHN0YWJsZSBjb25maWd1cmF0aW9uCiAgICogKG9yIDwwIGlmIHdpdGhpbiBzdGFibGUgY29uZmlndXJhdGlvbiksCiAgICogZCBpcyB0aGUgY3VycmVudCBkaXN0YW5jZSB0cmF2ZWxsZWQgKi8KCiAgaWYgKGdyYXBoW2ldW2pdW2tdID49IDApIHsKICAgIC8vIHdlIGtub3cgaG93IHRvIHJlYWNoIGZpeHBvaW50IGZyb20gaGVyZSBpbiB0aGF0IG1hbnkgaG9wcwogICAgcmV0dXJuIGdyYXBoW2ldW2pdW2tdOwogIH0KICBpZiAoZ3JhcGhbaV1bal1ba10gPCAtMSkgewogICAgLy8gd2UgaGl0IHNvbWV0aGluZyBpbiB0aGUgY3VycmVudCBzdGFjawogICAgLy8gcmV0cmlldmUgdGhlIGN5Y2xlIGxlbmd0aCBmcm9tIHRoZSBjdXJyZW50IGQgYW5kIHN0b3JlIHZhbHVlCiAgICBpbnQgcGVyaW9kID0gZCArIGdyYXBoW2ldW2pdW2tdICsgMTsKICAgIHByaW50ZigiU3RhYmxlIGNvbmZpZ3VyYXRpb24gb2YgcGVyaW9kICVkOiAlYyVjJWMgYWxpYXMgJWQgJWQgJWRcbiIsCiAgICAgICAgcGVyaW9kLCBpLCBqLCBrLCBpLCBqLCBrKTsKICAgIC8vIHVud2luZCB0aGUgc3RhY2s6IHJldHVybiB0aGUgbmVnYXRpdmUgbGVuZ3RoIG9mIHRoZSBjeWNsZSBzbyB0aGF0IGFsbAogICAgLy8gY3ljbGUgbWVtYmVycyBhcmUgc2V0IHRvIHplcm8KICAgIHJldHVybiAtcGVyaW9kLTE7CiAgfQogIC8vIG1hcmsgdGhhdCB3ZSBhcmUgZXhwbG9yaW5nIHRoaXMgbm9kZSBhbmQgdGhlIGRpc3RhbmNlIHRyYXZlbGVkCiAgZ3JhcGhbaV1bal1ba10gPSAtMiAtIGQ7CiAgdW5zaWduZWQgY2hhciB1LHYsdzsKICB1ID0gKGkmfjB4MDMpPj4yOwogIHYgPSAoaSYweDAzKTw8NCB8IChqJn4weDBGKT4+NDsKICB3ID0gKGomMHgwRik8PDIgfCAoayZ+MHgzRik+PjY7CiAgaW50IHJldCA9IGV4cGxvcmUoYjY0W3VdLCBiNjRbdl0sIGI2NFt3XSwgZCsxKTsKICBpZiAocmV0ID49IDApIHsKICAgIC8vIG91ciBkaXN0YW5jZSB0byBzdGFibGUgaXMgb25lIHBsdXMgZGlzdGFuY2UgdG8gc3RhYmxlIG9mIG91ciBpbWFnZQogICAgZ3JhcGhbaV1bal1ba10gPSByZXQrMTsKICB9IGVsc2UgewogICAgLy8gd2UgYXJlIHVud2luZGluZyBhIHN0YWJsZSBjb25maWd1cmF0aW9uCiAgICBncmFwaFtpXVtqXVtrXSA9IDA7CiAgfQogIC8vIHJldHVybiBvdXIgZGlzdGFuY2UgdG8gc3RhYmxlLCBvciBjb250aW51ZSB1bndpbmRpbmcKICByZXR1cm4gcmV0KzE7Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyICoqYXJndikgewogIGludCBpLCBqLCBrOwogIC8vIGluaXRpYWxpemF0aW9uCiAgZm9yIChpPTA7IGk8MjU2OyBpKyspCiAgICBmb3IgKGo9MDsgajwyNTY7IGorKykKICAgICAgZm9yIChrPTA7IGs8MjU2OyBrKyspCiAgICAgICAgZ3JhcGhbaV1bal1ba10gPSAtMTsKICBpZiAoYXJnYyA9PSAyKSB7CiAgICAvLyBhIGN1c3RvbSB0YWJsZSBoYXMgYmVlbiBwYXNzZWQKICAgIGFzc2VydChzdHJsZW4oYXJndlsxXSkgPT0gNjQpOwogICAgYjY0ID0gYXJndlsxXTsKICB9CiAgaW50IG1heCA9IDA7CiAgaW50IHJldDsKICB1bnNpZ25lZCBjaGFyIHZhPTAsIHZiPTAsIHZjPTA7CiAgZm9yIChpPTA7IGk8MjU2OyBpKyspCiAgICBmb3IgKGo9MDsgajwyNTY7IGorKykKICAgICAgZm9yIChrPTA7IGs8MjU2OyBrKyspIHsKICAgICAgICByZXQgPSBleHBsb3JlKGksIGosIGssIDApOwogICAgICAgIGlmIChyZXQgPiBtYXgpIHsKICAgICAgICAgIG1heCA9IHJldDsKICAgICAgICAgIHZhID0gaTsgdmIgPSBqOyB2YyA9IGs7CiAgICAgICAgfQogICAgICB9CgogIC8vIHByaW50IHdoaWNoIGlzIHRoZSBsb25nZXN0IHdheSB0byByZWFjaCBhIHN0YWJsZSBjb25maWd1cmF0aW9uCiAgcHJpbnRmKCJMb25nZXN0IGNoYWluIGlzIGZyb20gJWQgJWQgJWQgKCVkIGhvcHMpXG4iLCB2YSwgdmIsIHZjLCBtYXgpOwogIHJldHVybiAwOwp9Cgo=