package inf101.v18.gfx.textmode; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.function.BiFunction; public class BlocksAndBoxes { public enum PixelOrder implements Iterable { LEFT_TO_RIGHT(8, 4, 2, 1), RIGHT_TO_LEFT(4, 8, 1, 2), LEFT_TO_RIGHT_UPWARDS(2, 1, 8, 4), RIGHT_TO_LEFT_UPWARDS(1, 2, 4, 8); private List order; private PixelOrder(int a, int b, int c, int d) { order = Arrays.asList(a, b, c, d); } @Override public Iterator iterator() { return order.iterator(); } } public static final String[] unicodeBlocks = { " ", "▗", "▖", "▄", "▝", "▐", "▞", "▟", "▘", "▚", "▌", "▙", "▀", "▜", "▛", "█", "▒" }; public static final int[] unicodeBlocks_NumPixels = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 2 }; public static final String unicodeBlocksString = String.join("", unicodeBlocks); public static final String BLOCK_EMPTY = " "; public static final String BLOCK_BOTTOM_RIGHT = "▗"; public static final String BLOCK_BOTTOM_LEFT = "▖"; public static final String BLOCK_BOTTOM = "▄"; public static final String BLOCK_TOP_RIGHT = "▝"; public static final String BLOCK_RIGHT = "▐"; public static final String BLOCK_DIAG_FORWARD = "▞"; public static final String BLOCK_REVERSE_TOP_LEFT = "▟"; public static final String BLOCK_TOP_LEFT = "▘"; public static final String BLOCK_DIAG_BACKWARD = "▚"; public static final String BLOCK_LEFT = "▌"; public static final String BLOCK_REVERSE_TOP_RIGHT = "▙"; public static final String BLOCK_TOP = "▀"; public static final String BLOCK_REVERSE_BOTTOM_LEFT = "▜"; public static final String BLOCK_REVERSE_BOTTOM_RIGHT = "▛"; public static final String BLOCK_FULL = "█"; public static final String BLOCK_HALF = "▒";; public static String blockAddOne(String s, PixelOrder order) { int i = BlocksAndBoxes.unicodeBlocksString.indexOf(s); if (i >= 0) { for (int bit : order) { if ((i & bit) == 0) return unicodeBlocks[i | bit]; } } return s; } /** * Convert a string into a Unicode block graphics character. * *

* The block characters corresponds to 2x2-pixel images, and can be used, e.g., * to draw a 80x44 pixel image on a 40x22 character text screen. * *

* The blocks are specified by four-character strings of spaces and asterisks, * with space indicating an open space and asterisk indicating a filled "pixel", * with the pixels arranged in a left-to-right, top-to-bottom order: * *

	 * 01
	 * 23
	 * 
* *

* So "* **" corresponds to the block character "▚", * with this layout: * *

	 * * 
	 *  *
	 * 
* *

* The special codes "++++" and "+" corresponds to the * "grey" block "▒", and "*" corresponds to the * "black" block "█". * * @param s * A four character string, indicating which block character to * select. * @return A Unicode block character * @throws IllegalArgumentException * if the string isn't of the expected form */ public static String blockChar(String s) { switch (s.replaceAll("\n", s)) { case " ": return unicodeBlocks[0]; case " *": return unicodeBlocks[1]; case " * ": return unicodeBlocks[2]; case " **": return unicodeBlocks[3]; case " * ": return unicodeBlocks[4]; case " * *": return unicodeBlocks[5]; case " ** ": return unicodeBlocks[6]; case " ***": return unicodeBlocks[7]; case "* ": return unicodeBlocks[8]; case "* *": return unicodeBlocks[9]; case "* * ": return unicodeBlocks[10]; case "* **": return unicodeBlocks[11]; case "** ": return unicodeBlocks[12]; case "** *": return unicodeBlocks[13]; case "*** ": return unicodeBlocks[14]; case "****": return unicodeBlocks[15]; case "++++": return unicodeBlocks[16]; case ".": return BLOCK_BOTTOM_LEFT; case "_": return BLOCK_BOTTOM; case "/": return BLOCK_DIAG_FORWARD; case "\\": return BLOCK_DIAG_BACKWARD; case "|": return BLOCK_LEFT; case "#": return BLOCK_FULL; case "`": return BLOCK_TOP_LEFT; case "'": return BLOCK_TOP_RIGHT; } throw new IllegalArgumentException( "Expected length 4 string of \" \" and \"*\", or \"++++\", got \"" + s + "\""); } public static String blockCompact(String s) { int i = BlocksAndBoxes.unicodeBlocksString.indexOf(s); if (i > 0) { int lower = i & 3; int upper = (i >> 2) & 3; i = (lower | upper) | ((lower & upper) << 2); // System.out.println("Compact: " + s + " -> " + BlocksAndBoxes.unicodeBlocks[i] // + "\n"); return BlocksAndBoxes.unicodeBlocks[i]; } return s; } public static String blockCompose(String b1, String b2, BiFunction op) { int i1 = unicodeBlocksString.indexOf(b1); if (i1 < 0) throw new IllegalArgumentException("Not a block character: " + b1); int i2 = unicodeBlocksString.indexOf(b2); if (i2 < 0) throw new IllegalArgumentException("Not a block character: " + b1); if (i1 == 16 || i2 == 16) return b2; else return unicodeBlocks[op.apply(i1, i2)]; } public static String blockComposeOrOverwrite(String b1, String b2, BiFunction op) { int i1 = unicodeBlocksString.indexOf(b1); int i2 = unicodeBlocksString.indexOf(b2); if (i1 < 0 || i2 < 0 || i1 == 16 || i2 == 16) return b2; else return unicodeBlocks[op.apply(i1, i2)]; } public static String blockRemoveOne(String s, PixelOrder order) { int i = BlocksAndBoxes.unicodeBlocksString.indexOf(s); if (i >= 0) { for (int bit : order) { if ((i & bit) != 0) return unicodeBlocks[i & ~bit]; } } return s; } }