FINISHED HUFFMAN FINALLLLLLYLYLLY

This commit is contained in:
Jacob Signorovitch
2025-01-13 13:56:01 -05:00
parent d9d937c77e
commit b6ec810bb9
3 changed files with 384 additions and 371 deletions

View File

@@ -38,19 +38,16 @@ class Examples {
void init2() {
// jacob itaru signorovitch
letters = new ArrayList<>(Arrays.asList(
"j", "a", "c", "o", "b", "i", "t", "r", "u", "s", "g", "n", "h", "v"
));
letters = new ArrayList<>(Arrays.asList("j", "a", "c", "o", "b", "i", "t",
"r", "u", "s", "g", "n", "h", "v"));
counts = new ArrayList<>(
Arrays.asList(1, 2, 2, 3, 1, 3, 2, 2, 1, 1, 1, 1, 1, 1)
);
Arrays.asList(1, 2, 2, 3, 1, 3, 2, 2, 1, 1, 1, 1, 1, 1));
}
void init3() {
// hello world
letters =
new ArrayList<>(Arrays.asList("h", "e", "l", "o", "w", "r", "d"));
letters = new ArrayList<>(Arrays.asList("h", "e", "l", "o", "w", "r", "d"));
counts = new ArrayList<>(Arrays.asList(1, 1, 3, 2, 1, 1, 1));
huff = new Huffman(letters, counts);
@@ -91,18 +88,14 @@ class Examples {
void testUtilInsertIntoSorted(Tester t) {
init();
Util.insertIntoSorted(c, treesSomeSorted);
t.checkExpect(
treesSomeSorted, new ArrayList<ITree>(Arrays.asList(c, e, d, f))
);
t.checkExpect(treesSomeSorted,
new ArrayList<ITree>(Arrays.asList(c, e, d, f)));
Util.insertIntoSorted(a, treesSomeSorted);
t.checkExpect(
treesSomeSorted, new ArrayList<ITree>(Arrays.asList(c, e, a, d, f))
);
t.checkExpect(treesSomeSorted,
new ArrayList<ITree>(Arrays.asList(c, e, a, d, f)));
Util.insertIntoSorted(b, treesSomeSorted);
t.checkExpect(
treesSomeSorted,
new ArrayList<ITree>(Arrays.asList(c, e, a, d, f, b))
);
t.checkExpect(treesSomeSorted,
new ArrayList<ITree>(Arrays.asList(c, e, a, d, f, b)));
Util.insertIntoSorted(j, treesSame);
t.checkExpect(treesSame, new ArrayList<ITree>(Arrays.asList(h, i, j)));
}
@@ -110,15 +103,11 @@ class Examples {
void testUtilInsert(Tester t) {
init();
Util.insert(a, treesFirstTwoSorted, 2);
t.checkExpect(
treesFirstTwoSorted,
new ArrayList<ITree>(Arrays.asList(c, e, a, b, f))
);
t.checkExpect(treesFirstTwoSorted,
new ArrayList<ITree>(Arrays.asList(c, e, a, b, f)));
Util.insert(g, treesFirstTwoSorted, 3);
t.checkExpect(
treesFirstTwoSorted,
new ArrayList<ITree>(Arrays.asList(c, e, a, g, b, f))
);
t.checkExpect(treesFirstTwoSorted,
new ArrayList<ITree>(Arrays.asList(c, e, a, g, b, f)));
}
void testUtilSort(Tester t) {
@@ -134,32 +123,23 @@ class Examples {
void testUtilEnlist(Tester t) {
String s = "Hello";
t.checkExpect(
Util.enlist(s),
new ArrayList<String>(Arrays.asList("H", "e", "l", "l", "o"))
);
t.checkExpect(Util.enlist(s), new ArrayList<String>(
Arrays.asList("H", "e", "l", "l", "o")));
String s2 = "h";
t.checkExpect(
Util.enlist(s2), new ArrayList<String>(Arrays.asList("h"))
);
t.checkExpect(Util.enlist(s2), new ArrayList<String>(Arrays.asList("h")));
}
void testHuffmanMkcode(Tester t) {
init();
Huffman h = new Huffman(
new ArrayList<String>(Arrays.asList("a", "b")),
new ArrayList<Integer>(Arrays.asList(1, 1))
);
Huffman h = new Huffman(new ArrayList<String>(Arrays.asList("a", "b")),
new ArrayList<Integer>(Arrays.asList(1, 1)));
t.checkExpect(
h.code, new Node(2, "b", new Leaf(1, "a"), new Leaf(1, "b"))
);
t.checkExpect(h.code, new Node(2, new Leaf(1, "a"), new Leaf(1, "b")));
Huffman h2 = new Huffman(
new ArrayList<String>(Arrays.asList("a", "b", "c", "d", "e")),
new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5))
);
new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5)));
// 1: a:1, b:2, c:3, d:4, e:5
// 2: (a:1|b:2):3, c:3, d:4, e:5
@@ -169,45 +149,60 @@ class Examples {
t.checkExpect(
h2.code,
new Node(
15, "e",
new Node(
6, "c",
new Node(3, "b", new Leaf(1, "a"), new Leaf(2, "b")),
new Leaf(3, "c")
),
new Node(9, "e", new Leaf(4, "d"), new Leaf(5, "e"))
)
);
new Node(15,
new Node(6, new Node(3, new Leaf(1, "a"), new Leaf(2, "b")),
new Leaf(3, "c")),
new Node(9, new Leaf(4, "d"), new Leaf(5, "e"))));
}
void testHuffmanEncode(Tester t) {
void testHuffmanEncodeAndAlsoDecodeAndAlsoEverythingElse(Tester t) {
init3();
t.checkExpect(
huff.code,
new Node(
10, "lrwdoeh",
10,
new Node(
4, "oeh",
new Node(2, "eh", new Leaf(1, "h"), new Leaf(1, "e")),
new Leaf(2, "o")
),
4,
new Node(
6, "lrwd",
2,
new Leaf(1, "h"), // //
new Leaf(1, "e")),
new Leaf(2, "o")),
new Node(
3, "rwd", new Leaf(1, "d"),
new Node(2, "rw", new Leaf(1, "w"), new Leaf(1, "r"))
),
new Leaf(3, "l")
)
)
);
6,
new Node(
3,
new Leaf(1, "d"), // //
new Node(
2,
new Leaf(1, "w"), // //
new Leaf(1, "r"))),
new Leaf(3, "l"))));
t.checkExpect(
huff.encode("he"), new ArrayList<Boolean>(Arrays.asList(
false, false, false, false, false, true
))
);
ArrayList<Boolean> path =
new ArrayList<>(Arrays.asList(false, false, false));
ArrayList<Boolean> path2 =
new ArrayList<>(Arrays.asList(false, false, false, false, false, true,
true, true, true, true, false, true));
ArrayList<Boolean> path3 = new ArrayList<>(
Arrays.asList(false, false, false, false, false, true, true, true, true,
true, false, true, true, false, true, false, false, true,
true, false, true, true, true, true, true, false, false));
t.checkExpect(huff.encode("h"), path);
t.checkExpect(huff.decode(path), "h");
t.checkExpect(huff.encode("hello"), path2);
t.checkExpect(huff.decode(path2), "hello");
t.checkExpect(huff.encode("helloworld"), path3);
t.checkExpect(huff.decode(path3), "helloworld");
Huffman huff2 = new Huffman("foo bar baz");
ArrayList<Boolean> enc = huff2.encode("booz farz fazz");
t.checkExpect(huff2.decode(enc), "booz farz fazz");
}
}
@@ -216,12 +211,13 @@ class Huffman {
ArrayList<String> charset; // Character set.
ArrayList<Integer> freqs; // Frequencies of characters in charset.
ITree code; // The tree allowing for encoding and decoding.
ArrayList<ArrayList<Boolean>> map; // Association between the charset and the
// path to reach that char in the code.
Huffman(ArrayList<String> charset, ArrayList<Integer> freqs) {
if (charset.size() != freqs.size())
throw new IllegalArgumentException(
"Character set must match frequencies."
);
"Character set must match frequencies.");
if (charset.size() < 2)
throw new IllegalArgumentException("Character set too small.");
@@ -229,7 +225,44 @@ class Huffman {
this.charset = charset;
this.freqs = freqs;
this.map = new ArrayList<>();
// Generate the code.
this.mkcode();
// Generate map.
this.mkmap();
}
// Generates character freqs from string.
Huffman(String data) {
if (data.length() <= 1)
throw new Error("Can't create tree from that.");
ArrayList<String> charset = new ArrayList<>();
ArrayList<Integer> freqs = new ArrayList<>();
for (int i = 0; i < data.length(); i++) {
// The current character.
String ch = data.substring(i, i + 1);
if (charset.contains(ch)) {
int j = charset.indexOf(ch);
freqs.set(j, freqs.get(j) + 1);
} else {
charset.add(ch);
freqs.add(1);
}
}
this.charset = charset;
this.freqs = freqs;
this.map = new ArrayList<>();
// Generate the code.
this.mkcode();
// Generate map.
this.mkmap();
}
// Creates the code tree.
@@ -250,10 +283,8 @@ class Huffman {
ITree secondLowest = nodes.get(1);
nodes.remove(firstLowest);
nodes.remove(secondLowest);
ITree parent = new Node(
firstLowest.sumFreq(secondLowest), firstLowest.getQuestion(),
firstLowest, secondLowest
);
ITree parent = new Node(firstLowest.sumFreq(secondLowest), firstLowest,
secondLowest);
// Put new tree into list.
nodes.add(0, parent);
@@ -263,34 +294,39 @@ class Huffman {
this.code = nodes.getFirst();
}
// Make the character path mapping.
void mkmap() {
for (String ch : this.charset)
this.map.addLast(this.code.encode(ch));
}
// Encode a message.
ArrayList<Boolean> encode(String s) {
System.out.println("Encoding " + s);
System.out.flush();
ArrayList<String> msg =
Util.enlist(s); // The given message, as a list of characters.
ArrayList<Boolean> enc =
new ArrayList<>(); // The returned encoded message.
ArrayList<Boolean> enc = new ArrayList<>(); // The returned encoded message.
// Loop for each character in the message.
for (String ch : msg) enc.addAll(this.encodeCh(ch));
for (String ch : msg)
enc.addAll(this.encodeCh(ch));
return enc;
}
// Encode a character.
ArrayList<Boolean> encodeCh(String ch) {
System.out.println("Encoding character " + ch);
System.out.flush();
// Throw error if character is not in charset.
if (!this.charset.contains(ch))
throw new IllegalArgumentException(
"Cannot encode unknown character \"" + ch + "\"."
);
throw new IllegalArgumentException("Cannot encode unknown character \"" +
ch + "\".");
return this.code.encode(ch);
int i = this.charset.indexOf(ch);
return this.map.get(i);
}
// Decode a message.
String decode(ArrayList<Boolean> enc) { return this.code.follow(enc); }
}
// Binary tree.
@@ -305,13 +341,13 @@ interface ITree {
int sumFreq(ITree t);
int sumFreq(int freq);
// Return its question (the values on the right).
String getQuestion();
// Encode a character.
ArrayList<Boolean> encode(String ch);
ArrayList<Boolean>
encodeHelper(String ch, ArrayList<Boolean> encodingSoFar);
ArrayList<Boolean> encode(String ch, ArrayList<Boolean> encodingSoFar);
// Follow (decode) a path.
String follow(ArrayList<Boolean> path);
String followCh(ArrayList<Boolean> path);
}
abstract class ATree implements ITree {
@@ -331,42 +367,52 @@ class Node extends ATree {
// Left (false) and right (true) branches of tree.
ITree l, r;
// The 'question' the node asks to determine whether to go left or right. If
// the character is in the string, go right.
String question;
Node(int freq, String question, ITree l, ITree r) {
Node(int freq, ITree l, ITree r) {
super(freq);
this.question = question;
this.l = l;
this.r = r;
}
public String getQuestion() { return this.question; }
public ArrayList<Boolean> encode(String ch) {
Boolean b = this.question.contains(ch);
System.out.println(
"I'm a node encoding " + ch + " and going " + (b ? "right" : "left")
);
System.out.flush();
// If the character's in the question, go right; otherwise, go left.
return this.question.contains(ch)
? this.r.encodeHelper(ch, new ArrayList<>(Arrays.asList(true)))
: this.l.encodeHelper(ch, new ArrayList<>(Arrays.asList(false)));
ArrayList<Boolean> ret = new ArrayList<>();
ret.addAll(this.l.encode(ch, new ArrayList<>(Arrays.asList(false))));
ret.addAll(this.r.encode(ch, new ArrayList<>(Arrays.asList(true))));
return ret;
}
public ArrayList<Boolean>
encodeHelper(String ch, ArrayList<Boolean> encodingSoFar) {
System.out.println("I'm a node encode helping " + ch);
System.out.flush();
Boolean contains = this.question.contains(ch);
public ArrayList<Boolean> encode(String ch,
ArrayList<Boolean> encodingSoFar) {
ArrayList<Boolean> ret = new ArrayList<>(),
left = new ArrayList<Boolean>(Arrays.asList(false)),
right = new ArrayList<>(Arrays.asList(true));
ITree choice = contains ? this.r : this.l;
encodingSoFar.add(contains);
left.addAll(0, encodingSoFar);
right.addAll(0, encodingSoFar);
return choice.encodeHelper(ch, encodingSoFar);
ret.addAll(this.l.encode(ch, left));
ret.addAll(this.r.encode(ch, right));
return ret;
}
public String follow(ArrayList<Boolean> path) {
String ret = "";
// Each loop is 1 character.
while (path.size() > 0) {
Boolean b = path.getFirst();
path.removeFirst();
ret += b ? this.r.followCh(path) : this.l.followCh(path);
}
return ret;
}
public String followCh(ArrayList<Boolean> path) {
if (path.size() <= 0)
throw new Error("Invalid path.");
Boolean b = path.getFirst();
path.removeFirst();
return b ? this.r.followCh(path) : this.l.followCh(path);
}
}
@@ -379,19 +425,24 @@ class Leaf extends ATree {
this.ch = ch;
}
public String getQuestion() { return this.ch; }
public ArrayList<Boolean> encode(String ch) {
System.out.println("I'm a leaf encoding " + ch);
System.out.flush();
throw new Error("Cannot encode a Leaf.");
throw new Error("Can't, fool.");
}
public ArrayList<Boolean>
encodeHelper(String ch, ArrayList<Boolean> encodingSoFar) {
System.out.println("I'm a leaf encode helping " + ch);
System.out.flush();
public ArrayList<Boolean> encode(String ch,
ArrayList<Boolean> encodingSoFar) {
if (ch.equals(this.ch))
return encodingSoFar;
else
return new ArrayList<Boolean>();
}
public String follow(ArrayList<Boolean> path) {
throw new Error("Shouldn't call follow() on leaf.");
}
public String followCh(ArrayList<Boolean> path) { return this.ch; }
public String follow(ArrayList<Boolean> path, String soFar) {
return soFar.concat(this.ch);
}
}
@@ -400,7 +451,8 @@ class Util {
// Sort a list of trees from least to most frequent.
static void sort(ArrayList<ITree> trees) {
// Our work here is done.
if (trees.size() < 2) return;
if (trees.size() < 2)
return;
for (int i = 1; i < trees.size(); i++) {
// Copy out the tree to insert.
@@ -419,7 +471,8 @@ class Util {
// Insert tree.
insertIntoSorted(tree, sorted);
// Overwrite original trees with sorted ones.
for (int j = 0; j < i; trees.set(j, sorted.get(j++)));
for (int j = 0; j < i; trees.set(j, sorted.get(j++)))
;
// Insert the last tree back in.
trees.add(i, sorted.getLast());
}
@@ -437,8 +490,8 @@ class Util {
// Convert a string to a list.
static ArrayList<String> enlist(String s) {
ArrayList<String> ret = new ArrayList<>();
for (int i = 0; i < s.length(); i++)
ret.add(String.valueOf(s.charAt(i)));
for (int i = 0; i < s.length(); ret.add(String.valueOf(s.charAt(i++))))
;
return ret;
}
}

View File

@@ -386,6 +386,7 @@ class Game extends World {
}
public Game onKeyEvent(String key) {
if (this.guessesLeft <= 0) throw new Error("Done.");
if ("123456789".contains(key)) { // User has entered a number.
int choice = Integer.valueOf(key);
if (choice <= this.conf.options.len()) return this.addDot(

View File

@@ -1,41 +0,0 @@
// Zed settings
//
// For information on how to configure Zed, see the Zed
// documentation: https://zed.dev/docs/configuring-zed
//
// To see all of Zed's default settings without changing your
// custom settings, run `zed: open default settings` from the
// command palette (cmd-shift-p / ctrl-shift-p)
{
// GENERAL SETTINGS
"outline_panel": {
"dock": "right"
},
"vim_mode": true,
// UI SETTINGS
"ui_font_size": 16,
"ui_font_family": "Iosevka Sans Ligless",
// BUFFER SETTINGS
"buffer_font_size": 16,
"buffer_font_family": "Iosevka Mono Ligless",
// BEHAVIOR SETTINGS
"languages": {
"Java": {
"formatter": {
"external": {
"command": "clang-format",
"arguments": ["--style=file", "--assume-filename={buffer_path}"]
}
},
"format_on_save": "on"
}
},
"wrap_guides": [80],
// MISC OTHER
"theme": {
"mode": "system",
"light": "Gruvbox Light",
"dark": "Gruvbox Dark"
}
}