commit
408bfb463a
16 changed files with 505 additions and 0 deletions
-
1.gitignore
-
23README.md
-
36atob.c
-
1bit.txt
-
46btoa.c
-
136jabber.c
-
BINkapow.txt
-
36make.sh
-
1out.txt
-
BINtable.jpg
-
1texts/hello.txt
-
116texts/hollow.txt
-
BINtexts/zeros.txt
-
BINtree.png
-
107wocky.c
-
1zap.txt
@ -0,0 +1 @@ |
|||
bin/ |
@ -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. |
|||
|
|||
 |
|||
|
|||
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. |
|||
|
|||
 |
|||
|
|||
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. |
@ -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); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
010010000110010101101100011011000110111100001010 |
@ -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; |
|||
} |
|||
} |
|||
} |
|||
|
@ -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); |
|||
} |
@ -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 |
|||
//// |
@ -0,0 +1 @@ |
|||
Hello |
After Width: 687 | Height: 500 | Size: 47 KiB |
@ -0,0 +1 @@ |
|||
Hello |
@ -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. |
After Width: 494 | Height: 288 | Size: 52 KiB |
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
0010101000110010101110011100011001001111101001010101101010100100100001 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue