From 37680804f26b562569b7d4b8e0a5fdebd5c32d88 Mon Sep 17 00:00:00 2001 From: Duncol Date: Sat, 23 Jan 2021 07:49:43 +0100 Subject: [PATCH 1/8] WIP Sophisticated model approach --- pom.xml | 10 ++++ src/main/java/BinaryTattoo.java | 29 +++++++++++ src/main/java/model/BinaryLetter.java | 47 +++++++++++++++++ src/main/java/model/BinaryPhrase.java | 52 +++++++++++++++++++ src/main/java/model/BinaryWord.java | 42 +++++++++++++++ .../java/model/HorizontalBinaryPhrase.java | 25 +++++++++ src/main/java/model/VerticalBinaryPhrase.java | 26 ++++++++++ src/main/java/parser/BinaryParser.java | 47 +++++++++++++++++ src/main/java/parser/PrintDirection.java | 5 ++ 9 files changed, 283 insertions(+) create mode 100644 src/main/java/BinaryTattoo.java create mode 100644 src/main/java/model/BinaryLetter.java create mode 100644 src/main/java/model/BinaryPhrase.java create mode 100644 src/main/java/model/BinaryWord.java create mode 100644 src/main/java/model/HorizontalBinaryPhrase.java create mode 100644 src/main/java/model/VerticalBinaryPhrase.java create mode 100644 src/main/java/parser/BinaryParser.java create mode 100644 src/main/java/parser/PrintDirection.java diff --git a/pom.xml b/pom.xml index 3348a7f..3d993fb 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,17 @@ + + org.projectlombok + lombok + 1.18.16 + + + org.slf4j + slf4j-simple + 1.6.4 + \ No newline at end of file diff --git a/src/main/java/BinaryTattoo.java b/src/main/java/BinaryTattoo.java new file mode 100644 index 0000000..12d8ace --- /dev/null +++ b/src/main/java/BinaryTattoo.java @@ -0,0 +1,29 @@ +import lombok.extern.slf4j.Slf4j; +import model.BinaryPhrase; +import model.BinaryWord; +import parser.BinaryParser; +import parser.PrintDirection; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Slf4j +public class BinaryTattoo { + + public static void main(String[] args) { + + final String input = "FORTIS FORTUNA ADJUVAT"; + final String delimiter = " "; + + final List words = Stream.of(input.split(delimiter)) + .map(BinaryParser::parseBinaryWord).collect(Collectors.toList()); + + final BinaryPhrase phrase = new BinaryPhrase.Builder() + .words(words) + .direction(PrintDirection.VERTICAL) + .build(); + + phrase.printBits(); + } +} diff --git a/src/main/java/model/BinaryLetter.java b/src/main/java/model/BinaryLetter.java new file mode 100644 index 0000000..e4340fe --- /dev/null +++ b/src/main/java/model/BinaryLetter.java @@ -0,0 +1,47 @@ +package model; + +import java.util.ArrayDeque; +import java.util.Queue; + +public class BinaryLetter { + + private final Queue bits = new ArrayDeque<>(); + + /** + * Sets the next bit, from left to right. + * + * @param bit true (1), or false (0) + */ + public void appendBit(boolean bit) { + bits.add(bit); + } + + public boolean hasNextBit() { + return !bits.isEmpty(); + } + + public boolean pollNextBit() { + Boolean bit = bits.poll(); + if (bit == null) { + throw new IllegalArgumentException("No bits left!"); + } + return bit; + } + + /** + * Return the number of bits, that consists to the letter + * + * @return number of bits + */ + public int length() { + return bits.size(); + } + + @Override + public String toString() { + return bits.stream() + .map(bit -> bit ? "1" : "0") + .reduce(String::concat) + .orElse("!"); + } +} diff --git a/src/main/java/model/BinaryPhrase.java b/src/main/java/model/BinaryPhrase.java new file mode 100644 index 0000000..a934d1a --- /dev/null +++ b/src/main/java/model/BinaryPhrase.java @@ -0,0 +1,52 @@ +package model; + +import parser.PrintDirection; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Stream; + +public abstract class BinaryPhrase { + protected final boolean[][] bitMatrix; + protected int heightCursor = 0; + protected int widthCursor = 0; + + protected BinaryPhrase(int maxWidth, int maxHeight) { + this.bitMatrix = new boolean[maxHeight][maxWidth]; + } + + protected abstract void appendBitWord(BinaryWord word); + + public static class Builder { + private Collection words = new ArrayList<>(); + private PrintDirection direction = PrintDirection.HORIZONTAL; + + public Builder direction(PrintDirection d) { + this.direction = d; + return this; + } + + public Builder words(Collection words) { + this.words = words; + return this; + } + + public BinaryPhrase build() { + int longestWordLength = words.stream().map(BinaryWord::length).reduce(Integer::sum).orElse(0); + int wordCount = words.size(); + int delimiterCount = wordCount-1; + + if (PrintDirection.HORIZONTAL.equals(direction)) { + return new HorizontalBinaryPhrase(longestWordLength, wordCount, words); + } else { + return new VerticalBinaryPhrase(wordCount, longestWordLength, words); + } + } + } + + public void printBits() { + Stream.of(bitMatrix).map(Arrays::toString).forEach(System.out::println); + } +} + diff --git a/src/main/java/model/BinaryWord.java b/src/main/java/model/BinaryWord.java new file mode 100644 index 0000000..edbd4f9 --- /dev/null +++ b/src/main/java/model/BinaryWord.java @@ -0,0 +1,42 @@ +package model; + +import java.util.ArrayDeque; +import java.util.Queue; + +public class BinaryWord { + + private final Queue letters = new ArrayDeque<>(); + + public void appendLetter(BinaryLetter letter) { + letters.add(letter); + } + + public boolean hasNextLetter() { + return !letters.isEmpty(); + } + + public BinaryLetter pollNextLetter() { + BinaryLetter letter = letters.poll(); + if (letter == null) { + throw new IllegalArgumentException("No letters left!"); + } + return letter; + } + + /** + * Return the number of bits, that consists to the word + * + * @return number of bits + */ + public int length() { + return letters.stream().map(BinaryLetter::length).reduce(Integer::sum).orElse(0); + } + + @Override + public String toString() { + return letters.stream() + .map(BinaryLetter::toString) + .reduce((letter1, letter2) -> letter1 + " " + letter2) + .orElse("EMPTY"); + } +} diff --git a/src/main/java/model/HorizontalBinaryPhrase.java b/src/main/java/model/HorizontalBinaryPhrase.java new file mode 100644 index 0000000..2a959ed --- /dev/null +++ b/src/main/java/model/HorizontalBinaryPhrase.java @@ -0,0 +1,25 @@ +package model; + +import java.util.Collection; + +public class HorizontalBinaryPhrase extends BinaryPhrase { + + public HorizontalBinaryPhrase(int maxHeight, int maxWidth, Collection words) { + super(maxWidth, maxHeight); + words.forEach(this::appendBitWord); + } + + @Override + protected void appendBitWord(BinaryWord word) { + + while (word.hasNextLetter()) { + BinaryLetter letter = word.pollNextLetter(); + while (letter.hasNextBit()) { + boolean bit = letter.pollNextBit(); + bitMatrix[heightCursor][widthCursor] = bit; + widthCursor++; + } + heightCursor++; + } + } +} diff --git a/src/main/java/model/VerticalBinaryPhrase.java b/src/main/java/model/VerticalBinaryPhrase.java new file mode 100644 index 0000000..d656820 --- /dev/null +++ b/src/main/java/model/VerticalBinaryPhrase.java @@ -0,0 +1,26 @@ +package model; + +import java.util.Collection; + +public class VerticalBinaryPhrase extends BinaryPhrase { + + public VerticalBinaryPhrase(int maxWidth, int maxHeight, Collection words) { + super(maxWidth, maxHeight); + words.forEach(this::appendBitWord); + } + + @Override + protected void appendBitWord(BinaryWord word) { + + while (word.hasNextLetter()) { + BinaryLetter letter = word.pollNextLetter(); + while (letter.hasNextBit()) { + boolean bit = letter.pollNextBit(); + bitMatrix[heightCursor][widthCursor] = bit; + heightCursor++; + } + + } + widthCursor++; + } +} diff --git a/src/main/java/parser/BinaryParser.java b/src/main/java/parser/BinaryParser.java new file mode 100644 index 0000000..3053cad --- /dev/null +++ b/src/main/java/parser/BinaryParser.java @@ -0,0 +1,47 @@ +package parser; + +import lombok.extern.slf4j.Slf4j; +import model.BinaryLetter; +import model.BinaryWord; + +@Slf4j +public class BinaryParser { + + private static final char SPACE = ' '; + + public static BinaryWord parseBinaryWord(String input) { + log.info("Parsing input: {}", input); + long startTime = System.currentTimeMillis(); + + BinaryWord word = new BinaryWord(); + for (char c : input.toCharArray()) { + word.appendLetter(parseBinaryLetter(c)); + } + + long duration = System.currentTimeMillis() - startTime; + log.info("Parsing complete, result: {} (took: {}ms)", word, duration); + return word; + } + + private static BinaryLetter parseBinaryLetter(char input) { + int divider = 1; + + // Find closest binary incrementation, i.e. 8, 16, 32 etc... + while (input > divider) { + divider *= 2; + } + + BinaryLetter letter = new BinaryLetter(); + while (divider > 0) { + if (input >= divider) { + letter.appendBit(true); + input -= divider; + } else { + letter.appendBit(false); + } + divider /= 2; + } + + return letter; + } +} diff --git a/src/main/java/parser/PrintDirection.java b/src/main/java/parser/PrintDirection.java new file mode 100644 index 0000000..b891749 --- /dev/null +++ b/src/main/java/parser/PrintDirection.java @@ -0,0 +1,5 @@ +package parser; + +public enum PrintDirection { + HORIZONTAL, VERTICAL +} From eee0ebff685044b7d203be878db733cdb3dade27 Mon Sep 17 00:00:00 2001 From: Duncol Date: Sat, 23 Jan 2021 10:11:54 +0100 Subject: [PATCH 2/8] Working (no separators yet) --- src/main/java/BinaryTattoo.java | 1 + src/main/java/model/HorizontalBinaryPhrase.java | 4 ++-- src/main/java/model/VerticalBinaryPhrase.java | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/BinaryTattoo.java b/src/main/java/BinaryTattoo.java index 12d8ace..cbbf870 100644 --- a/src/main/java/BinaryTattoo.java +++ b/src/main/java/BinaryTattoo.java @@ -21,6 +21,7 @@ public static void main(String[] args) { final BinaryPhrase phrase = new BinaryPhrase.Builder() .words(words) +// .direction(PrintDirection.HORIZONTAL) .direction(PrintDirection.VERTICAL) .build(); diff --git a/src/main/java/model/HorizontalBinaryPhrase.java b/src/main/java/model/HorizontalBinaryPhrase.java index 2a959ed..46908cd 100644 --- a/src/main/java/model/HorizontalBinaryPhrase.java +++ b/src/main/java/model/HorizontalBinaryPhrase.java @@ -4,7 +4,7 @@ public class HorizontalBinaryPhrase extends BinaryPhrase { - public HorizontalBinaryPhrase(int maxHeight, int maxWidth, Collection words) { + public HorizontalBinaryPhrase(int maxWidth, int maxHeight, Collection words) { super(maxWidth, maxHeight); words.forEach(this::appendBitWord); } @@ -19,7 +19,7 @@ protected void appendBitWord(BinaryWord word) { bitMatrix[heightCursor][widthCursor] = bit; widthCursor++; } - heightCursor++; } + heightCursor++; } } diff --git a/src/main/java/model/VerticalBinaryPhrase.java b/src/main/java/model/VerticalBinaryPhrase.java index d656820..7e48c72 100644 --- a/src/main/java/model/VerticalBinaryPhrase.java +++ b/src/main/java/model/VerticalBinaryPhrase.java @@ -19,7 +19,6 @@ protected void appendBitWord(BinaryWord word) { bitMatrix[heightCursor][widthCursor] = bit; heightCursor++; } - } widthCursor++; } From eca19a8c8dc285d4c9601f357b10ad6c55b28618 Mon Sep 17 00:00:00 2001 From: Duncol Date: Sat, 23 Jan 2021 10:41:35 +0100 Subject: [PATCH 3/8] Basic phrase tests + remove unused local var --- pom.xml | 8 ++++ src/main/java/model/BinaryPhrase.java | 1 - src/test/java/parser/BinaryPhraseTest.java | 44 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/test/java/parser/BinaryPhraseTest.java diff --git a/pom.xml b/pom.xml index 3d993fb..9cc2e32 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,14 @@ slf4j-simple 1.6.4 + + + org.junit.jupiter + junit-jupiter-engine + 5.5.2 + test + + \ No newline at end of file diff --git a/src/main/java/model/BinaryPhrase.java b/src/main/java/model/BinaryPhrase.java index a934d1a..3c2e474 100644 --- a/src/main/java/model/BinaryPhrase.java +++ b/src/main/java/model/BinaryPhrase.java @@ -35,7 +35,6 @@ public Builder words(Collection words) { public BinaryPhrase build() { int longestWordLength = words.stream().map(BinaryWord::length).reduce(Integer::sum).orElse(0); int wordCount = words.size(); - int delimiterCount = wordCount-1; if (PrintDirection.HORIZONTAL.equals(direction)) { return new HorizontalBinaryPhrase(longestWordLength, wordCount, words); diff --git a/src/test/java/parser/BinaryPhraseTest.java b/src/test/java/parser/BinaryPhraseTest.java new file mode 100644 index 0000000..1b12c48 --- /dev/null +++ b/src/test/java/parser/BinaryPhraseTest.java @@ -0,0 +1,44 @@ +package parser; + +import model.*; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class BinaryPhraseTest { + + @Test + public void verticalTest() { + + // given + Collection emptyWordCollection = new ArrayList<>(); + + // when + final BinaryPhrase phrase = new BinaryPhrase.Builder() + .words(emptyWordCollection) + .direction(PrintDirection.VERTICAL) + .build(); + + // then + assertEquals(VerticalBinaryPhrase.class, phrase.getClass()); + } + + @Test + public void horizontalTest() { + + // given + Collection emptyWordCollection = new ArrayList<>(); + + // when + final BinaryPhrase phrase = new BinaryPhrase.Builder() + .words(emptyWordCollection) + .direction(PrintDirection.HORIZONTAL) + .build(); + + // then + assertEquals(HorizontalBinaryPhrase.class, phrase.getClass()); + } +} From 10a0bfc6f286cc172d9334e8150d43885c5dba19 Mon Sep 17 00:00:00 2001 From: Duncol Date: Sat, 23 Jan 2021 22:20:02 +0100 Subject: [PATCH 4/8] Return String instead of print, 'empty' chars present (need to replace arrays with some humane collection); extracted PhraseBuilder to a separate class. --- src/main/java/BinaryTattoo.java | 12 +++-- src/main/java/model/BinaryPhrase.java | 51 ------------------- .../java/model/HorizontalBinaryPhrase.java | 25 --------- src/main/java/model/VerticalBinaryPhrase.java | 25 --------- src/main/java/model/phrase/BinaryPhrase.java | 20 ++++++++ .../model/phrase/BinaryPhraseBuilder.java | 40 +++++++++++++++ .../model/phrase/HorizontalBinaryPhrase.java | 46 +++++++++++++++++ .../model/phrase/VerticalBinaryPhrase.java | 46 +++++++++++++++++ src/test/java/parser/BinaryPhraseTest.java | 8 ++- 9 files changed, 165 insertions(+), 108 deletions(-) delete mode 100644 src/main/java/model/BinaryPhrase.java delete mode 100644 src/main/java/model/HorizontalBinaryPhrase.java delete mode 100644 src/main/java/model/VerticalBinaryPhrase.java create mode 100644 src/main/java/model/phrase/BinaryPhrase.java create mode 100644 src/main/java/model/phrase/BinaryPhraseBuilder.java create mode 100644 src/main/java/model/phrase/HorizontalBinaryPhrase.java create mode 100644 src/main/java/model/phrase/VerticalBinaryPhrase.java diff --git a/src/main/java/BinaryTattoo.java b/src/main/java/BinaryTattoo.java index cbbf870..5e53cbc 100644 --- a/src/main/java/BinaryTattoo.java +++ b/src/main/java/BinaryTattoo.java @@ -1,5 +1,6 @@ import lombok.extern.slf4j.Slf4j; -import model.BinaryPhrase; +import model.phrase.BinaryPhrase; +import model.phrase.BinaryPhraseBuilder; import model.BinaryWord; import parser.BinaryParser; import parser.PrintDirection; @@ -14,17 +15,18 @@ public class BinaryTattoo { public static void main(String[] args) { final String input = "FORTIS FORTUNA ADJUVAT"; - final String delimiter = " "; + final String separator = " "; - final List words = Stream.of(input.split(delimiter)) + final List words = Stream.of(input.split(separator)) .map(BinaryParser::parseBinaryWord).collect(Collectors.toList()); - final BinaryPhrase phrase = new BinaryPhrase.Builder() + final BinaryPhrase phrase = new BinaryPhraseBuilder() .words(words) + .separator(separator) // .direction(PrintDirection.HORIZONTAL) .direction(PrintDirection.VERTICAL) .build(); - phrase.printBits(); + System.out.println(phrase.toString()); } } diff --git a/src/main/java/model/BinaryPhrase.java b/src/main/java/model/BinaryPhrase.java deleted file mode 100644 index 3c2e474..0000000 --- a/src/main/java/model/BinaryPhrase.java +++ /dev/null @@ -1,51 +0,0 @@ -package model; - -import parser.PrintDirection; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.stream.Stream; - -public abstract class BinaryPhrase { - protected final boolean[][] bitMatrix; - protected int heightCursor = 0; - protected int widthCursor = 0; - - protected BinaryPhrase(int maxWidth, int maxHeight) { - this.bitMatrix = new boolean[maxHeight][maxWidth]; - } - - protected abstract void appendBitWord(BinaryWord word); - - public static class Builder { - private Collection words = new ArrayList<>(); - private PrintDirection direction = PrintDirection.HORIZONTAL; - - public Builder direction(PrintDirection d) { - this.direction = d; - return this; - } - - public Builder words(Collection words) { - this.words = words; - return this; - } - - public BinaryPhrase build() { - int longestWordLength = words.stream().map(BinaryWord::length).reduce(Integer::sum).orElse(0); - int wordCount = words.size(); - - if (PrintDirection.HORIZONTAL.equals(direction)) { - return new HorizontalBinaryPhrase(longestWordLength, wordCount, words); - } else { - return new VerticalBinaryPhrase(wordCount, longestWordLength, words); - } - } - } - - public void printBits() { - Stream.of(bitMatrix).map(Arrays::toString).forEach(System.out::println); - } -} - diff --git a/src/main/java/model/HorizontalBinaryPhrase.java b/src/main/java/model/HorizontalBinaryPhrase.java deleted file mode 100644 index 46908cd..0000000 --- a/src/main/java/model/HorizontalBinaryPhrase.java +++ /dev/null @@ -1,25 +0,0 @@ -package model; - -import java.util.Collection; - -public class HorizontalBinaryPhrase extends BinaryPhrase { - - public HorizontalBinaryPhrase(int maxWidth, int maxHeight, Collection words) { - super(maxWidth, maxHeight); - words.forEach(this::appendBitWord); - } - - @Override - protected void appendBitWord(BinaryWord word) { - - while (word.hasNextLetter()) { - BinaryLetter letter = word.pollNextLetter(); - while (letter.hasNextBit()) { - boolean bit = letter.pollNextBit(); - bitMatrix[heightCursor][widthCursor] = bit; - widthCursor++; - } - } - heightCursor++; - } -} diff --git a/src/main/java/model/VerticalBinaryPhrase.java b/src/main/java/model/VerticalBinaryPhrase.java deleted file mode 100644 index 7e48c72..0000000 --- a/src/main/java/model/VerticalBinaryPhrase.java +++ /dev/null @@ -1,25 +0,0 @@ -package model; - -import java.util.Collection; - -public class VerticalBinaryPhrase extends BinaryPhrase { - - public VerticalBinaryPhrase(int maxWidth, int maxHeight, Collection words) { - super(maxWidth, maxHeight); - words.forEach(this::appendBitWord); - } - - @Override - protected void appendBitWord(BinaryWord word) { - - while (word.hasNextLetter()) { - BinaryLetter letter = word.pollNextLetter(); - while (letter.hasNextBit()) { - boolean bit = letter.pollNextBit(); - bitMatrix[heightCursor][widthCursor] = bit; - heightCursor++; - } - } - widthCursor++; - } -} diff --git a/src/main/java/model/phrase/BinaryPhrase.java b/src/main/java/model/phrase/BinaryPhrase.java new file mode 100644 index 0000000..bcf5db5 --- /dev/null +++ b/src/main/java/model/phrase/BinaryPhrase.java @@ -0,0 +1,20 @@ +package model.phrase; + +import model.BinaryWord; + +public abstract class BinaryPhrase { + protected static final int BIT_RANGE = 8; + + protected final boolean[][] bitMatrix; + protected int heightCursor = 0; + protected int widthCursor = 0; + protected final String separator; + + protected BinaryPhrase(int maxWidth, int maxHeight, String separator) { + this.bitMatrix = new boolean[maxHeight][maxWidth]; + this.separator = separator; + } + + protected abstract void appendBitWord(BinaryWord word); +} + diff --git a/src/main/java/model/phrase/BinaryPhraseBuilder.java b/src/main/java/model/phrase/BinaryPhraseBuilder.java new file mode 100644 index 0000000..047d98e --- /dev/null +++ b/src/main/java/model/phrase/BinaryPhraseBuilder.java @@ -0,0 +1,40 @@ +package model.phrase; + +import model.BinaryWord; +import parser.PrintDirection; + +import java.util.ArrayList; +import java.util.Collection; + +public class BinaryPhraseBuilder { + + private Collection words = new ArrayList<>(); + private PrintDirection direction = PrintDirection.HORIZONTAL; + private String separator; + + public BinaryPhraseBuilder direction(PrintDirection d) { + this.direction = d; + return this; + } + + public BinaryPhraseBuilder words(Collection words) { + this.words = words; + return this; + } + + public BinaryPhraseBuilder separator(String separator) { + this.separator = separator; + return this; + } + + public BinaryPhrase build() { + int longestWordLength = words.stream().map(BinaryWord::length).reduce(Integer::max).orElse(0); + int wordCount = words.size(); + + if (PrintDirection.HORIZONTAL.equals(direction)) { + return new HorizontalBinaryPhrase(longestWordLength, wordCount, separator, words); + } else { + return new VerticalBinaryPhrase(wordCount, longestWordLength, separator, words); + } + } +} diff --git a/src/main/java/model/phrase/HorizontalBinaryPhrase.java b/src/main/java/model/phrase/HorizontalBinaryPhrase.java new file mode 100644 index 0000000..c4250a0 --- /dev/null +++ b/src/main/java/model/phrase/HorizontalBinaryPhrase.java @@ -0,0 +1,46 @@ +package model.phrase; + +import model.BinaryLetter; +import model.BinaryWord; + +import java.util.Collection; + +public class HorizontalBinaryPhrase extends BinaryPhrase { + + public HorizontalBinaryPhrase(int maxWidth, int maxHeight, String separator, Collection words) { + super(maxWidth, maxHeight, separator); + words.forEach(this::appendBitWord); + } + + @Override + protected void appendBitWord(BinaryWord word) { + + while (word.hasNextLetter()) { + BinaryLetter letter = word.pollNextLetter(); + while (letter.hasNextBit()) { + boolean bit = letter.pollNextBit(); + bitMatrix[heightCursor][widthCursor] = bit; + widthCursor++; + } + } + widthCursor = 0; + heightCursor++; + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + for (boolean[] row : bitMatrix) { + for (int j = 0; j < row.length; j++) { + sb.append(row[j] ? '1' : '0'); + if ((j+1) % BIT_RANGE == 0) { + sb.append(separator); + } + } + sb.append("\n"); + } + + return sb.toString(); + } +} diff --git a/src/main/java/model/phrase/VerticalBinaryPhrase.java b/src/main/java/model/phrase/VerticalBinaryPhrase.java new file mode 100644 index 0000000..f1c4606 --- /dev/null +++ b/src/main/java/model/phrase/VerticalBinaryPhrase.java @@ -0,0 +1,46 @@ +package model.phrase; + +import model.BinaryLetter; +import model.BinaryWord; + +import java.util.Collection; + +public class VerticalBinaryPhrase extends BinaryPhrase { + + public VerticalBinaryPhrase(int maxWidth, int maxHeight, String separator, Collection words) { + super(maxWidth, maxHeight, separator); + words.forEach(this::appendBitWord); + } + + @Override + protected void appendBitWord(BinaryWord word) { + + while (word.hasNextLetter()) { + BinaryLetter letter = word.pollNextLetter(); + while (letter.hasNextBit()) { + boolean bit = letter.pollNextBit(); + bitMatrix[heightCursor][widthCursor] = bit; + heightCursor++; + } + } + heightCursor = 0; + widthCursor++; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < bitMatrix.length; i++) { + boolean[] row = bitMatrix[i]; + for (boolean b : row) { + sb.append(b ? '1' : '0').append(separator); + } + if ((i+1) % BIT_RANGE == 0) { + sb.append("\n"); + } + sb.append("\n"); + } + + return sb.toString(); + } +} diff --git a/src/test/java/parser/BinaryPhraseTest.java b/src/test/java/parser/BinaryPhraseTest.java index 1b12c48..e55130f 100644 --- a/src/test/java/parser/BinaryPhraseTest.java +++ b/src/test/java/parser/BinaryPhraseTest.java @@ -1,6 +1,10 @@ package parser; import model.*; +import model.phrase.BinaryPhrase; +import model.phrase.BinaryPhraseBuilder; +import model.phrase.HorizontalBinaryPhrase; +import model.phrase.VerticalBinaryPhrase; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -17,7 +21,7 @@ public void verticalTest() { Collection emptyWordCollection = new ArrayList<>(); // when - final BinaryPhrase phrase = new BinaryPhrase.Builder() + final BinaryPhrase phrase = new BinaryPhraseBuilder() .words(emptyWordCollection) .direction(PrintDirection.VERTICAL) .build(); @@ -33,7 +37,7 @@ public void horizontalTest() { Collection emptyWordCollection = new ArrayList<>(); // when - final BinaryPhrase phrase = new BinaryPhrase.Builder() + final BinaryPhrase phrase = new BinaryPhraseBuilder() .words(emptyWordCollection) .direction(PrintDirection.HORIZONTAL) .build(); From e64ba304e6aabe31fd4636c6f955946ccd3a9dae Mon Sep 17 00:00:00 2001 From: Duncol Date: Sun, 24 Jan 2021 11:33:41 +0100 Subject: [PATCH 5/8] Some more tests; added some validation (letter); added mockito; --- pom.xml | 7 ++ src/main/java/{parser => }/BinaryParser.java | 12 +- src/main/java/BinaryTattoo.java | 7 +- src/main/java/model/BinaryLetter.java | 38 ++++-- .../model/phrase/BinaryPhraseBuilder.java | 1 - .../model/phrase/HorizontalBinaryPhrase.java | 1 - .../phrase}/PrintDirection.java | 2 +- src/test/java/BinaryParserTest.java | 33 ++++++ src/test/java/model/BinaryLetterTest.java | 96 +++++++++++++++ src/test/java/model/BinaryWordTest.java | 87 ++++++++++++++ .../phrase/BinaryPhraseBuilderTest.java} | 10 +- .../java/model/phrase/BinaryPhraseTest.java | 112 ++++++++++++++++++ 12 files changed, 376 insertions(+), 30 deletions(-) rename src/main/java/{parser => }/BinaryParser.java (82%) rename src/main/java/{parser => model/phrase}/PrintDirection.java (72%) create mode 100644 src/test/java/BinaryParserTest.java create mode 100644 src/test/java/model/BinaryLetterTest.java create mode 100644 src/test/java/model/BinaryWordTest.java rename src/test/java/{parser/BinaryPhraseTest.java => model/phrase/BinaryPhraseBuilderTest.java} (81%) create mode 100644 src/test/java/model/phrase/BinaryPhraseTest.java diff --git a/pom.xml b/pom.xml index 9cc2e32..ae8c3ad 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,13 @@ test + + org.mockito + mockito-all + 1.10.19 + test + + \ No newline at end of file diff --git a/src/main/java/parser/BinaryParser.java b/src/main/java/BinaryParser.java similarity index 82% rename from src/main/java/parser/BinaryParser.java rename to src/main/java/BinaryParser.java index 3053cad..f8bf35d 100644 --- a/src/main/java/parser/BinaryParser.java +++ b/src/main/java/BinaryParser.java @@ -1,5 +1,3 @@ -package parser; - import lombok.extern.slf4j.Slf4j; import model.BinaryLetter; import model.BinaryWord; @@ -7,8 +5,6 @@ @Slf4j public class BinaryParser { - private static final char SPACE = ' '; - public static BinaryWord parseBinaryWord(String input) { log.info("Parsing input: {}", input); long startTime = System.currentTimeMillis(); @@ -31,17 +27,17 @@ private static BinaryLetter parseBinaryLetter(char input) { divider *= 2; } - BinaryLetter letter = new BinaryLetter(); + BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder(); while (divider > 0) { if (input >= divider) { - letter.appendBit(true); + letterBuilder.appendBit(true); input -= divider; } else { - letter.appendBit(false); + letterBuilder.appendBit(false); } divider /= 2; } - return letter; + return letterBuilder.build(); } } diff --git a/src/main/java/BinaryTattoo.java b/src/main/java/BinaryTattoo.java index 5e53cbc..47277cc 100644 --- a/src/main/java/BinaryTattoo.java +++ b/src/main/java/BinaryTattoo.java @@ -2,8 +2,7 @@ import model.phrase.BinaryPhrase; import model.phrase.BinaryPhraseBuilder; import model.BinaryWord; -import parser.BinaryParser; -import parser.PrintDirection; +import model.phrase.PrintDirection; import java.util.List; import java.util.stream.Collectors; @@ -23,8 +22,8 @@ public static void main(String[] args) { final BinaryPhrase phrase = new BinaryPhraseBuilder() .words(words) .separator(separator) -// .direction(PrintDirection.HORIZONTAL) - .direction(PrintDirection.VERTICAL) + .direction(PrintDirection.HORIZONTAL) +// .direction(PrintDirection.VERTICAL) .build(); System.out.println(phrase.toString()); diff --git a/src/main/java/model/BinaryLetter.java b/src/main/java/model/BinaryLetter.java index e4340fe..e56c6f6 100644 --- a/src/main/java/model/BinaryLetter.java +++ b/src/main/java/model/BinaryLetter.java @@ -5,15 +5,10 @@ public class BinaryLetter { - private final Queue bits = new ArrayDeque<>(); + private final Queue bits; - /** - * Sets the next bit, from left to right. - * - * @param bit true (1), or false (0) - */ - public void appendBit(boolean bit) { - bits.add(bit); + private BinaryLetter(Builder b) { + this.bits = b.bits; } public boolean hasNextBit() { @@ -44,4 +39,31 @@ public String toString() { .reduce(String::concat) .orElse("!"); } + + public static class Builder { + private int bitRange = 8; + private final Queue bits = new ArrayDeque<>(); + + public Builder bitRange(int bitRange) { + this.bitRange = bitRange; + return this; + } + + /** + * Sets the next bit, from left to right. + * + * @param bit true (1), or false (0) + */ + public Builder appendBit(boolean bit) { + bits.add(bit); + return this; + } + + public BinaryLetter build() throws IllegalArgumentException { + if (bitRange < 1 || bits.size() != bitRange) { + throw new IllegalArgumentException("Invalid bit range!"); + } + return new BinaryLetter(this); + } + } } diff --git a/src/main/java/model/phrase/BinaryPhraseBuilder.java b/src/main/java/model/phrase/BinaryPhraseBuilder.java index 047d98e..44fdd78 100644 --- a/src/main/java/model/phrase/BinaryPhraseBuilder.java +++ b/src/main/java/model/phrase/BinaryPhraseBuilder.java @@ -1,7 +1,6 @@ package model.phrase; import model.BinaryWord; -import parser.PrintDirection; import java.util.ArrayList; import java.util.Collection; diff --git a/src/main/java/model/phrase/HorizontalBinaryPhrase.java b/src/main/java/model/phrase/HorizontalBinaryPhrase.java index c4250a0..6a50b08 100644 --- a/src/main/java/model/phrase/HorizontalBinaryPhrase.java +++ b/src/main/java/model/phrase/HorizontalBinaryPhrase.java @@ -29,7 +29,6 @@ protected void appendBitWord(BinaryWord word) { @Override public String toString() { - StringBuilder sb = new StringBuilder(); for (boolean[] row : bitMatrix) { for (int j = 0; j < row.length; j++) { diff --git a/src/main/java/parser/PrintDirection.java b/src/main/java/model/phrase/PrintDirection.java similarity index 72% rename from src/main/java/parser/PrintDirection.java rename to src/main/java/model/phrase/PrintDirection.java index b891749..3188f22 100644 --- a/src/main/java/parser/PrintDirection.java +++ b/src/main/java/model/phrase/PrintDirection.java @@ -1,4 +1,4 @@ -package parser; +package model.phrase; public enum PrintDirection { HORIZONTAL, VERTICAL diff --git a/src/test/java/BinaryParserTest.java b/src/test/java/BinaryParserTest.java new file mode 100644 index 0000000..835b80e --- /dev/null +++ b/src/test/java/BinaryParserTest.java @@ -0,0 +1,33 @@ +import model.BinaryWord; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BinaryParserTest { + + @Test + public void parseWordTest() { + // given + final int defaultBitRange = 8; + String rawWord = "miscellaneous"; + + // when + BinaryWord parsedWord = BinaryParser.parseBinaryWord(rawWord); + + // then + assertEquals(rawWord.length(), parsedWord.length()/defaultBitRange); + } + + @Test + public void parseEmptyWordTest() { + // given + final int defaultBitRange = 8; + String rawWord = ""; + + // when + BinaryWord parsedWord = BinaryParser.parseBinaryWord(rawWord); + + // then + assertEquals(0, parsedWord.length()/defaultBitRange); + } +} \ No newline at end of file diff --git a/src/test/java/model/BinaryLetterTest.java b/src/test/java/model/BinaryLetterTest.java new file mode 100644 index 0000000..cefe1ed --- /dev/null +++ b/src/test/java/model/BinaryLetterTest.java @@ -0,0 +1,96 @@ +package model; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BinaryLetterTest { + + @Test + public void appendOnlyTest() { + + // given + BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder().bitRange(1); + letterBuilder.appendBit(true); + + // when + BinaryLetter letter = letterBuilder.build(); + + // then + assertEquals(1, letter.length()); + assertTrue(letter.hasNextBit()); + } + + @Test + public void appendAndPollTest() { + + // given + boolean bit = true; + BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder().bitRange(1); + letterBuilder.appendBit(true); + BinaryLetter letter = letterBuilder.build(); + + // when + boolean polledBit = letter.pollNextBit(); + + // then + assertEquals(bit, polledBit); + assertEquals(0, letter.length()); + assertFalse(letter.hasNextBit()); + } + + @Test + public void lengthTest() { + + // given + int bitsToAppend = 5; + int bitsToPoll = 3; + BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder().bitRange(bitsToAppend); + + // when + for (int i = 0; i < bitsToAppend; i++) { + letterBuilder.appendBit(true); + } + + BinaryLetter letter = letterBuilder.build(); + for (int i = 0; i < bitsToPoll; i++) { + letter.pollNextBit(); + } + + // then + assertEquals(2, letter.length()); + } + + @Test + public void buildEmptyLetterTest() { + + // given + BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder(); + + // when / then + assertThrows(IllegalArgumentException.class, letterBuilder::build); + } + + @Test + public void negativeBitRangeTest() { + + // given + BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder().bitRange(-1); + + // when / then + assertThrows(IllegalArgumentException.class, letterBuilder::build); + } + + @Test + public void incompleteLetterTest() { + + // given + BinaryLetter.Builder letterBuilder = new BinaryLetter.Builder() + .bitRange((byte)8) + .appendBit(true) + .appendBit(false); + + // when / then + assertThrows(IllegalArgumentException.class, letterBuilder::build); + } +} diff --git a/src/test/java/model/BinaryWordTest.java b/src/test/java/model/BinaryWordTest.java new file mode 100644 index 0000000..668b1ae --- /dev/null +++ b/src/test/java/model/BinaryWordTest.java @@ -0,0 +1,87 @@ +package model; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class BinaryWordTest { + + @Test + public void appendOnlyTest() { + + int bitsCountInLetter = 8; + + // given + BinaryLetter letterMock = mock(BinaryLetter.class); + when(letterMock.length()).thenReturn(bitsCountInLetter); + + // when + BinaryWord word = new BinaryWord(); + word.appendLetter(letterMock); + + // then + assertEquals(bitsCountInLetter, word.length()); + assertTrue(word.hasNextLetter()); + } + + @Test + public void appendAndPollTest() { + + // given + int bitsCountInLetter = 8; + + BinaryLetter letterMock = mock(BinaryLetter.class); + when(letterMock.length()).thenReturn(bitsCountInLetter); + + BinaryWord word = new BinaryWord(); + word.appendLetter(letterMock); + + // when + BinaryLetter polledLetter = word.pollNextLetter(); + + // then + assertEquals(letterMock, polledLetter); + assertEquals(0, word.length()); + assertFalse(word.hasNextLetter()); + } + + @Test + public void lengthTest() { + + // given + int bitsCountInLetter = 8; + int lettersToAppend = 5; + int lettersToPoll = 3; + + BinaryLetter letterMock = mock(BinaryLetter.class); + when(letterMock.length()).thenReturn(bitsCountInLetter); + + BinaryWord word = new BinaryWord(); + + // when + for (int i = 0; i < lettersToAppend; i++) { + word.appendLetter(letterMock); + } + + for (int i = 0; i < lettersToPoll; i++) { + word.pollNextLetter(); + } + + // then + assertEquals((lettersToAppend-lettersToPoll)*bitsCountInLetter, word.length()); + } + + @Test + public void pollBitEmptyLetterTest() { + + // given + BinaryWord word = new BinaryWord(); + + // when / then + assertEquals(0, word.length()); + assertFalse(word.hasNextLetter()); + assertThrows(IllegalArgumentException.class, word::pollNextLetter); + } +} \ No newline at end of file diff --git a/src/test/java/parser/BinaryPhraseTest.java b/src/test/java/model/phrase/BinaryPhraseBuilderTest.java similarity index 81% rename from src/test/java/parser/BinaryPhraseTest.java rename to src/test/java/model/phrase/BinaryPhraseBuilderTest.java index e55130f..e258793 100644 --- a/src/test/java/parser/BinaryPhraseTest.java +++ b/src/test/java/model/phrase/BinaryPhraseBuilderTest.java @@ -1,10 +1,6 @@ -package parser; +package model.phrase; -import model.*; -import model.phrase.BinaryPhrase; -import model.phrase.BinaryPhraseBuilder; -import model.phrase.HorizontalBinaryPhrase; -import model.phrase.VerticalBinaryPhrase; +import model.BinaryWord; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -12,7 +8,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class BinaryPhraseTest { +class BinaryPhraseBuilderTest { @Test public void verticalTest() { diff --git a/src/test/java/model/phrase/BinaryPhraseTest.java b/src/test/java/model/phrase/BinaryPhraseTest.java new file mode 100644 index 0000000..53c1b66 --- /dev/null +++ b/src/test/java/model/phrase/BinaryPhraseTest.java @@ -0,0 +1,112 @@ +package model.phrase; + +import model.*; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BinaryPhraseTest { + + private static final String SEPARATOR = " "; + + @Test + public void emptyTest() { + // given + Collection words = new ArrayList<>(); + + // when + final BinaryPhrase phrase = new BinaryPhraseBuilder() + .words(words) + .direction(PrintDirection.VERTICAL) + .build(); + + // then + String actual = phrase.toString(); + assertEquals("", actual); + } + +// @Test + public void verticalTest() { + + String expected = "01000110" + SEPARATOR + "01001111" + SEPARATOR + "01010010" + SEPARATOR + "01010100" + SEPARATOR + "01001001" + SEPARATOR + "01010011" + SEPARATOR + "00000000" + SEPARATOR + "\n" + + "01000110" + SEPARATOR + "01001111" + SEPARATOR + "01010010" + SEPARATOR + "01010100" + SEPARATOR + "01010101" + SEPARATOR + "01001110" + SEPARATOR + "01000001 \n" + + "01000001" + SEPARATOR + "01000100" + SEPARATOR + "01001010" + SEPARATOR + "01010101" + SEPARATOR + "01010110" + SEPARATOR + "01000001" + SEPARATOR + "01010100 "; + + // given + Collection words = new ArrayList<>(); + + // when + final BinaryPhrase phrase = new BinaryPhraseBuilder() + .words(words) + .direction(PrintDirection.VERTICAL) + .build(); + + // then + String actual = phrase.toString(); + assertEquals(expected, actual); + } + +// @Test + public void horizontalTest() { + + String expected = "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" + + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "1" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" + + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + "\n" + + "1" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" + + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "1" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "1" + SEPARATOR + "\n" + + "0" + SEPARATOR + "0" + SEPARATOR + "0" + SEPARATOR + "\n" + + "0" + SEPARATOR + "1" + SEPARATOR + "0" + SEPARATOR + ""; + + // given + Collection words = new ArrayList<>(); + + // when + final BinaryPhrase phrase = new BinaryPhraseBuilder() + .words(words) + .direction(PrintDirection.HORIZONTAL) + .build(); + + // then + assertEquals(expected, phrase.toString()); + } +} From 363000eaac06017a8c8ce7eb9e24f166cd85cce3 Mon Sep 17 00:00:00 2001 From: Duncol Date: Sun, 24 Jan 2021 15:22:05 +0100 Subject: [PATCH 6/8] Extracted main() method; added mvn packaging --- pom.xml | 42 +++++++++++++++++++++++++++++++++ src/main/java/BinaryTattoo.java | 12 ++++------ src/main/java/Main.java | 11 +++++++++ 3 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 src/main/java/Main.java diff --git a/pom.xml b/pom.xml index ae8c3ad..bed6a7f 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,41 @@ 8 + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + Main + + + + + + + maven-assembly-plugin + + + + Main + + + + jar-with-dependencies + + + + + package + + single + + + + @@ -47,6 +82,13 @@ test + + commons-cli + commons-cli + 1.4 + + + \ No newline at end of file diff --git a/src/main/java/BinaryTattoo.java b/src/main/java/BinaryTattoo.java index 47277cc..99fb493 100644 --- a/src/main/java/BinaryTattoo.java +++ b/src/main/java/BinaryTattoo.java @@ -11,21 +11,17 @@ @Slf4j public class BinaryTattoo { - public static void main(String[] args) { + public String toBinaryString(String source, String separator, PrintDirection printDirection) { - final String input = "FORTIS FORTUNA ADJUVAT"; - final String separator = " "; - - final List words = Stream.of(input.split(separator)) + final List words = Stream.of(source.split(separator)) .map(BinaryParser::parseBinaryWord).collect(Collectors.toList()); final BinaryPhrase phrase = new BinaryPhraseBuilder() .words(words) .separator(separator) - .direction(PrintDirection.HORIZONTAL) -// .direction(PrintDirection.VERTICAL) + .direction(printDirection) .build(); - System.out.println(phrase.toString()); + return phrase.toString(); } } diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 0000000..f397bb7 --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,11 @@ +import model.phrase.PrintDirection; + +public class Main { + + private static final PrintDirection DIRECTION = PrintDirection.VERTICAL; + private static final String SEPARATOR = " "; + + public static void main(String[] args) { + System.out.println(new BinaryTattoo().toBinaryString(args[0], SEPARATOR, DIRECTION)); + } +} From cb39129a9d304386dfcb74a5ce0d0dcb838de03f Mon Sep 17 00:00:00 2001 From: Duncol Date: Sun, 24 Jan 2021 15:23:16 +0100 Subject: [PATCH 7/8] Added /target to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1bc94f3..d08c7af 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* /.idea/ +/target \ No newline at end of file From 3f86f78694590f05be30ba028548015be42c6adf Mon Sep 17 00:00:00 2001 From: Duncol Date: Sat, 6 Feb 2021 09:30:34 +0100 Subject: [PATCH 8/8] Added CMD line parser (see: README.MD) --- README.md | 9 ++- src/main/java/BinaryTattoo.java | 14 ++-- src/main/java/CmdLineTattooParser.java | 88 ++++++++++++++++++++++++++ src/main/java/Main.java | 13 ++-- src/main/java/model/TattooData.java | 18 ++++++ 5 files changed, 130 insertions(+), 12 deletions(-) create mode 100644 src/main/java/CmdLineTattooParser.java create mode 100644 src/main/java/model/TattooData.java diff --git a/README.md b/README.md index 5e07913..d4c303d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # BinaryTattoo -Transform text into it's binary representation (ASCII) in many ways! +Transform text into it's binary representation (ASCII) in many ways with this lovely little cmd line tool! + +# Usage +* '-i' (required) - input to be binarized (string; might some wise sentence, like 'I never don't give up') +* '-s' (optional) - separator you want to use in between the binary words (I discourage to use '0' or '1', for obvious reasons). Defaults to ' ' (single space) +* '-d' (optional) - the direction in which the binarized tattoo will be printed. Available options in 2D world are: 'HORIZONTAL' and 'VERTICAL'. Sorry non-euclideans... + +Have any suggestions? Well, I don't care, this is my baby and I will implement only the things I want (or even less, due to procrastination) diff --git a/src/main/java/BinaryTattoo.java b/src/main/java/BinaryTattoo.java index 99fb493..0a0d1e5 100644 --- a/src/main/java/BinaryTattoo.java +++ b/src/main/java/BinaryTattoo.java @@ -1,8 +1,8 @@ import lombok.extern.slf4j.Slf4j; +import model.BinaryWord; +import model.TattooData; import model.phrase.BinaryPhrase; import model.phrase.BinaryPhraseBuilder; -import model.BinaryWord; -import model.phrase.PrintDirection; import java.util.List; import java.util.stream.Collectors; @@ -11,15 +11,17 @@ @Slf4j public class BinaryTattoo { - public String toBinaryString(String source, String separator, PrintDirection printDirection) { + private static final String DEFAULT_SEPARAOR = " "; + + public static String toBinaryString(TattooData tattooData) { - final List words = Stream.of(source.split(separator)) + final List words = Stream.of(tattooData.tattooString().split(DEFAULT_SEPARAOR)) .map(BinaryParser::parseBinaryWord).collect(Collectors.toList()); final BinaryPhrase phrase = new BinaryPhraseBuilder() .words(words) - .separator(separator) - .direction(printDirection) + .separator(tattooData.separator()) + .direction(tattooData.printDirection()) .build(); return phrase.toString(); diff --git a/src/main/java/CmdLineTattooParser.java b/src/main/java/CmdLineTattooParser.java new file mode 100644 index 0000000..ad72c2b --- /dev/null +++ b/src/main/java/CmdLineTattooParser.java @@ -0,0 +1,88 @@ +import lombok.extern.slf4j.Slf4j; +import model.TattooData; +import model.phrase.PrintDirection; +import org.apache.commons.cli.*; + +import java.util.Arrays; +import java.util.stream.Collectors; + +@Slf4j +public class CmdLineTattooParser { + + public static final String INPUT_FLAG = "i"; + public static final String INPUT_FLAG_DESCRIPTION = "input string to be binarized"; + + public static final String SEPARATOR_FLAG = "s"; + public static final String SEPARATOR_FLAG_DESCRIPTION = "word separator (default: space, i.e. ' ')"; + public static final String DEFAULT_SEPARATOR = " "; + + public static final String DIRECTION_FLAG = "d"; + public static final String DIRECTION_FLAG_DESCRIPTION = "print direction (default: vertical)"; + public static final PrintDirection DEFAULT_DIRECTION = PrintDirection.VERTICAL; + + public TattooData readArgs(String[] args) throws ParseException { + Options cmdOptions = buildOptions(); + try { + CommandLine parsedArgs = new DefaultParser().parse(cmdOptions, args); + + return parseTattooData(parsedArgs); + } catch (IllegalArgumentException ex) { + String generalMessage = String.format("Unable to parse input, cause: %s", ex.getMessage()); + printHelp(generalMessage, cmdOptions); + throw new ParseException(generalMessage); + } + } + + private Options buildOptions() { + Options cmdOptions = new Options(); + cmdOptions.addOption(new Option(INPUT_FLAG, true, INPUT_FLAG_DESCRIPTION)); + cmdOptions.addOption(new Option(SEPARATOR_FLAG, true, SEPARATOR_FLAG_DESCRIPTION)); + cmdOptions.addOption(new Option(DIRECTION_FLAG, true, DIRECTION_FLAG_DESCRIPTION)); + return cmdOptions; + } + + private TattooData parseTattooData(CommandLine parsedArgs) { + String tattooString = parsedArgs.getOptionValue(INPUT_FLAG); + if (tattooString == null || tattooString.isEmpty()) { + throw new IllegalArgumentException("Input tattoo string cannot be empty!"); + } + if (tattooString.length() > 100000) { + throw new IllegalArgumentException("Seriously? You don't have long enough body for this shit"); + } + + log.trace("Provided tattooString is correct: '{}'", tattooString); + TattooData tattooData = new TattooData(tattooString); + + String separator = parsedArgs.getOptionValue(SEPARATOR_FLAG); + if (separator == null || separator.isEmpty()) { + log.warn("You've provided empty separator, defaulting to '{}'", DEFAULT_SEPARATOR); + tattooData.separator(DEFAULT_SEPARATOR); + } else { + if (separator.length() > 100) { + log.warn("Seriously? Such long separation should only be between you and this program.."); + tattooData.separator(DEFAULT_SEPARATOR); + } else { + log.trace("Provided separator is correct: '{}'", separator); + tattooData.separator(separator); + } + } + + try { + String directionString = parsedArgs.getOptionValue(DIRECTION_FLAG); + tattooData.printDirection(PrintDirection.valueOf(directionString)); + log.trace("Provided print direction is correct: '{}'", directionString); + } catch (IllegalArgumentException ex) { + log.error("Invalid print direction specified, allowed values: {}, defaulting to: {}", + Arrays.stream(PrintDirection.values()).map(PrintDirection::toString).collect(Collectors.joining(",")), + DEFAULT_DIRECTION); + tattooData.printDirection(DEFAULT_DIRECTION); + } + + return tattooData; + } + + private void printHelp(String generalMessage, Options options) { + log.error(generalMessage); + new HelpFormatter().printHelp("[packaged_jar]", options); + } +} diff --git a/src/main/java/Main.java b/src/main/java/Main.java index f397bb7..fb0534f 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -1,11 +1,14 @@ -import model.phrase.PrintDirection; +import model.TattooData; +import org.apache.commons.cli.ParseException; public class Main { - private static final PrintDirection DIRECTION = PrintDirection.VERTICAL; - private static final String SEPARATOR = " "; - public static void main(String[] args) { - System.out.println(new BinaryTattoo().toBinaryString(args[0], SEPARATOR, DIRECTION)); + try { + TattooData tattooData = new CmdLineTattooParser().readArgs(args); + System.out.println(BinaryTattoo.toBinaryString(tattooData)); + } catch (ParseException ex) { + // CmdLineTattooParser print help message, we just want to 'Enjoy the silence' here + } } } diff --git a/src/main/java/model/TattooData.java b/src/main/java/model/TattooData.java new file mode 100644 index 0000000..1b981c2 --- /dev/null +++ b/src/main/java/model/TattooData.java @@ -0,0 +1,18 @@ +package model; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import model.phrase.PrintDirection; + +@Setter +@Getter +@Accessors(fluent = true) +@RequiredArgsConstructor +public class TattooData { + + private final String tattooString; + private String separator; + private PrintDirection printDirection; +}