Browse Source

Finished jabberwocky

master
ChristopherMahoney2000 2 years ago
commit
408bfb463a
  1. 1
      .gitignore
  2. 23
      README.md
  3. 36
      atob.c
  4. 1
      bit.txt
  5. 46
      btoa.c
  6. 136
      jabber.c
  7. BIN
      kapow.txt
  8. 36
      make.sh
  9. 1
      out.txt
  10. BIN
      table.jpg
  11. 1
      texts/hello.txt
  12. 116
      texts/hollow.txt
  13. BIN
      texts/zeros.txt
  14. BIN
      tree.png
  15. 107
      wocky.c
  16. 1
      zap.txt

1
.gitignore

@ -0,0 +1 @@
bin/

23
README.md

@ -0,0 +1,23 @@
# Jabberwocky
In order to run my code you can simply call `./make.sh <file>`. The files `bit.txt`, `zap.txt`, `kapow.txt` and `out.txt` will be generated in order.
My implementation for both jabber and wocky used the same fact about our compression table. Every prefix we add to our table was one bit appended to some previously seen prefix. This allows for some cool data structures.
**Jabber**
TJ had the idea to use a labeled binary tree that we can descend while reading in the prefix. Reading in a zero means descending left and reading a one descends right. Once we reach a leaf node we print it's label in binary and we add a new child node in the direction of the next bit, labeled with tree size + 1.
![](tree.png)
Using a binary tree in this way means the time complexity for reading in a prefix is proportional to the length of the prefix and not directly related to the size of the tree.
Ryan and I worked together on implementing Jabber but we wrote our own code.
**Wocky**
I wrote wocky alone and once again used the "each prefix = some previous prefix + 1 bit" property. Since at each step we read an index (integer) and find the prefix (string) at that index an array of cstrings would be sufficent. `char ** table = malloc(size * sizeof(char*))`. This can be done more memory efficently. Instead of storing cstrings I store a pointer to the previous prefix and 1 character representing the 1 new bit.
![](table.jpg)
Printing becomes a little more complicated since we can no longer just fprintf a cstring. All it requires is a little bit of recursive decent, unfortunately this can't be written tail recursively.
**atob and btoa**
I tried to optimize as much as possible without digging into assembly and calculating running times. They use lots of bit wise opperators.

36
atob.c

@ -0,0 +1,36 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void atob ( FILE *ifp, FILE *ofp );
int main( int argc, char *argv[] ) {
FILE *ifp, *ofp;
if (argc < 3) {
fprintf(stderr, "Not enough arguments\n");
exit(1);
}
if (!(ifp = fopen(argv[1],"r"))) {
fprintf(stderr,"Cannot open file %s\n",argv[1]);
exit(1);
}
if (!(ofp = fopen(argv[2],"w"))) {
fprintf(stderr,"Cannot open file %s\n",argv[2]);
exit(1);
}
atob(ifp, ofp);
return 0;
}
void atob ( FILE *ifp, FILE *ofp ) {
char c;
while ((c = fgetc(ifp)) != EOF) {
char i;
for (i = 7; i >= 0; --i) {
fputc('0' + (c >> i & 1), ofp);
}
}
}

1
bit.txt

@ -0,0 +1 @@
010010000110010101101100011011000110111100001010

46
btoa.c

@ -0,0 +1,46 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void btoa ( FILE *ifp, FILE *ofp );
int main( int argc, char *argv[] ) {
FILE *ifp, *ofp;
if (argc < 3) {
fprintf(stderr, "Not enough arguments\n");
exit(1);
}
if (!(ifp = fopen(argv[1],"r"))) {
fprintf(stderr,"Cannot open file %s\n",argv[1]);
exit(1);
}
if (!(ofp = fopen(argv[2],"w"))) {
fprintf(stderr,"Cannot open file %s\n",argv[2]);
exit(1);
}
btoa(ifp, ofp);
return 0;
}
void btoa( FILE *ifp, FILE *ofp ) {
char c;
char byte = 0;
unsigned char mask = 1 << 7;
while ((c = fgetc(ifp)) != EOF) {
if (c == '1') {
byte |= mask;
}
if (!(mask >>= 1)) {
fputc(byte, ofp);
byte = 0;
mask = 1 << 7;
}
}
}

136
jabber.c

@ -0,0 +1,136 @@
#include <stdio.h>
#include <stdlib.h>
void jabber ( FILE *ifp, FILE *ofp );
int main( int argc, char *argv[] ) {
FILE *ifp, *ofp;
if (argc < 3) {
fprintf(stderr, "Not enough arguments\n");
exit(1);
}
if (!(ifp = fopen(argv[1],"r"))) {
fprintf(stderr,"Cannot open file %s\n",argv[1]);
exit(1);
}
if (!(ofp = fopen(argv[2],"w"))) {
fprintf(stderr,"Cannot open file %s\n",argv[2]);
exit(1);
}
jabber(ifp, ofp);
return 0;
}
typedef struct node_t {
int index;
// Children
struct node_t * zero;
struct node_t * one;
} node;
node * new_node( int index ) {
node * n = malloc(sizeof(node));
n -> index = index;
n -> zero = NULL;
n -> one = NULL;
return n;
}
void printTree(node * curr, int depth);
void jabber( FILE *ifp, FILE *ofp ) {
// Read the entire file into a buffer
fseek(ifp, 0L, SEEK_END);
long sz = ftell(ifp);
rewind(ifp);
char * buffer = malloc(sz);
fread(buffer, 1, sz, ifp);
// Start the tree
node * root = new_node(0);
node * cursor = root;
int index = 0;
int bits = 0;
for (int i = 0; i < sz; ++i) {
char c = buffer[i];
if (c == '0') {
if (cursor -> zero == NULL) {
// Print index
for (int j = bits - 1; j >= 0; --j) {
fputc('0' + ((cursor -> index >> j) & 1), ofp);
}
// Append next bit
fputc('0', ofp);
// Create new node
cursor -> zero = new_node(++index);
} else {
// Step down
cursor = cursor -> zero;
continue;
}
} else if (c == '1') {
if (cursor -> one == NULL) {
// Print index
for (int j = bits - 1; j >= 0; --j) {
fputc('0' + ((cursor -> index >> j) & 1), ofp);
}
// Append next bit
fputc('1', ofp);
// Create new node
cursor -> one = new_node(++index);
} else {
// Step down
cursor = cursor -> one;
continue;
}
} else {
fprintf(stderr, "Invalid character");
exit(1);
}
// Update bits if needed
if (1 << bits & index)
++bits;
// Reset the cursor
cursor = root;
}
// Final index
for (int j = bits - 1; j >= 0; --j) {
fputc('0' + ((cursor -> index >> j) & 1), ofp);
}
printTree(root, 0);
}
int rec[1000000];
void printTree(node * curr, int depth)
{
int i;
if(curr==NULL)return;
printf("\t");
for(i=0;i<depth;i++)
if(i==depth-1)
printf("%s---",rec[depth-1]?"L":"R");
else
printf("%s ",rec[i]?"|":" ");
printf("%d\n",curr->index);
rec[depth]=1;
printTree(curr->zero,depth+1);
rec[depth]=0;
printTree(curr->one,depth+1);
}

BIN
kapow.txt

36
make.sh

@ -0,0 +1,36 @@
#!/bin/sh
# Compile
gcc atob.c -g -o bin/atob
gcc jabber.c -g -o bin/jabber
gcc wocky.c -g -o bin/wocky
gcc btoa.c -g -o bin/btoa
# Run in order
./bin/atob ${1} bit.txt
./bin/jabber bit.txt zap.txt
./bin/wocky zap.txt kapow.txt
./bin/btoa kapow.txt out.txt
# Print all
<< ////
echo --${1}--
cat ${1}
echo
echo --bit-${1}--
cat bit.txt
echo
echo --zap-${1}--
cat zap.txt
echo
echo --kapow-${1}--
cat kapow.txt
echo
echo --out.txt--
cat out.txt
echo
////

1
out.txt

@ -0,0 +1 @@
Hello

BIN
table.jpg

After

Width: 687  |  Height: 500  |  Size: 47 KiB

1
texts/hello.txt

@ -0,0 +1 @@
Hello

116
texts/hollow.txt

@ -0,0 +1,116 @@
The Hollow Men.
We are the hollow men
We are the stuffed men
Leaning together
Headpiece filled with straw. Alas!
Our dried voices, when
We whisper together
Are quiet and meaningless
As wind in dry grass
Or rats' feet over broken glass
in our dry cellar
Shape without form, shade without colour,
Paralysed force, gesture without motion;
Those who have crossed
With direct eyes, to death's other Kingdom
Remember us --- if at all --- not as lost
Violent souls, but only
As the hollow men
The stuffed men.
Eyes I dare not meet in dreams
In death's dream kingdom
These do not appear:
There, the eyes are
Sunlight on a broken column
There, is a tree swinging
And voices are
In the wind's singing
More distant and more solemn
Than a fading star.
Let me be no nearer
In death's dream kingdom
Let me also wear
Such deliberate disguises
Rat's coat, crowskin, crossed staves
In a field
Behaving as the wind behaves
No nearer ---
Not that final meeting
In the twilight kingdom
This is the dead land
This is cactus land
Here the stone images
Are raised, here they receive
The supplication of a dead man's hand
Under the twinkle of a fading star.
Is it like this
In death's other kingdom
Waking alone
At the hour when we are
Trembling with tenderness
Lips that would kiss
Form prayers to broken stone.
The eyes are not here
There are no eyes here
In this valley of dying stars
In this hollow valley
This broken jaw of our lost kingdoms
In this last of meeting places
We grope together
And avoid speech
Gathered on this beach of the tumid river
Sightless, unless
The eyes reappear
As the perpetual star
Multifoliate rose
Of death's twilight kingdom
The hope only
Of empty men.
Here we go around the prickly pear
Prickly pear prickly pear
Here we go around the prickly pear
At five o'clock in the morning.
Between the idea
And the reality
Between the motion
And the act
Falls the Shadow
For Thine is the Kingdom
Between the conception
And the creation
Between the emotion
And the response
Falls the Shadow
Life is very long
Between the desire
And the spasm
Between the potency
And the existence
Between the essence
And the descent
Falls the Shadow
For Thine is the Kingdom
For Thine is
Life is
For Thine is the
This is the way the world ends
This is the way the world ends
This is the way the world ends
Not with a bang but with a whimper.

BIN
texts/zeros.txt

BIN
tree.png

After

Width: 494  |  Height: 288  |  Size: 52 KiB

107
wocky.c

@ -0,0 +1,107 @@
#include <stdio.h>
#include <stdlib.h>
void wocky ( FILE *ifp, FILE *ofp );
int main( int argc, char *argv[] ) {
FILE *ifp, *ofp;
if (argc < 3) {
fprintf(stderr, "Not enough arguments\n");
exit(1);
}
if (!(ifp = fopen(argv[1],"r"))) {
fprintf(stderr,"Cannot open file %s\n",argv[1]);
exit(1);
}
if (!(ofp = fopen(argv[2],"w"))) {
fprintf(stderr,"Cannot open file %s\n",argv[2]);
exit(1);
}
wocky(ifp, ofp);
return 0;
}
typedef struct element_t {
char c;
struct element_t * prefix;
} element;
element * new_element( element * prefix, char c ) {
element * e = malloc(sizeof(element));
e -> prefix = prefix;
e -> c = c;
return e;
}
// Print a prefix using some recursion
void fprint_element(FILE *fp, element * e) {
if (e -> prefix != NULL) {
fprint_element(fp, e -> prefix);
fputc(e -> c, fp);
}
}
void wocky ( FILE *ifp, FILE *ofp ) {
// Read the entire file into a buffer
fseek(ifp, 0L, SEEK_END);
long sz = ftell(ifp);
rewind(ifp);
char * buffer = malloc(sz);
fread(buffer, 1, sz, ifp);
// Start the table of prefixes
element ** table = malloc(sizeof(element*));
table[0] = new_element(NULL, '\0');
int t_length = 1;
int t_capacity = 1;
int index = 0; // Index of prefix
int length = 0; // Number of bits index will be represented in
int read = 0; // Number of bits currently read
char c;
for (int i = 0; i <= sz; ++i) {
c = buffer[i];
if (read == length) {
// Print prefix at index
fprint_element(ofp, table[index]);
// Grow table if full
if (t_length == t_capacity) {
// Double capacity
element ** new_table = malloc(2 * t_capacity * sizeof(element*));
for (int j = 0; j < t_capacity; ++j) {
new_table[j] = table[j];
}
free(table);
table = new_table;
t_capacity *= 2;
}
// Add new prefix
table[t_length++] = new_element(table[index], c);
element * e = table[t_length - 1];
// Print bit
fputc(c, ofp);
// Length increases when max index requires more bits to represent
if ((t_length - 1) & (1 << length) || length == 0) {
++length;
}
read = 0;
index = 0;
} else {
++read;
if (c == '1') {
index += 1 << (length - read);
}
}
}
}

1
zap.txt

@ -0,0 +1 @@
0010101000110010101110011100011001001111101001010101101010100100100001
Loading…
Cancel
Save