diff --git a/src/main/java/pkovacs/util/data/AbstractTable.java b/src/main/java/pkovacs/util/data/AbstractTable.java index 6be71ad..1e9b668 100644 --- a/src/main/java/pkovacs/util/data/AbstractTable.java +++ b/src/main/java/pkovacs/util/data/AbstractTable.java @@ -34,6 +34,8 @@ public int size() { abstract void set0(int row, int col, T value); + abstract AbstractTable newInstance(int rowCount, int colCount, BiFunction function); + /** * Returns true if this table contains the given cell. */ @@ -119,4 +121,48 @@ public void updateAll(Function function) { } } + /** + * Mirrors this table horizontally: the row indices remain the same, while column indices are flipped. + * A new table is generated and returned, this table is not changed. + */ + public AbstractTable mirrorHorizontally() { + int colCount = colCount(); + return newInstance(rowCount(), colCount, (i, j) -> get0(i, colCount - 1 - j)); + } + + /** + * Mirrors this table vertically: the column indices remain the same, while the row indices are flipped. + * A new table is generated and returned, this table is not changed. + */ + public AbstractTable mirrorVertically() { + int rowCount = rowCount(); + return newInstance(rowCount, colCount(), (i, j) -> get0(rowCount - 1 - i, j)); + } + + /** + * Rotates this table to the right (clockwise). + * A new table is generated and returned, this table is not changed. + */ + public AbstractTable rotateRight() { + int rowCount = rowCount(); + return newInstance(colCount(), rowCount(), (i, j) -> get0(rowCount - 1 - j, i)); + } + + /** + * Rotates this table to the left (counter-clockwise). + * A new table is generated and returned, this table is not changed. + */ + public AbstractTable rotateLeft() { + int colCount = colCount(); + return newInstance(colCount(), rowCount(), (i, j) -> get0(j, colCount - 1 - i)); + } + + /** + * Transposes this table: turns rows into columns and vice versa. + * A new table is generated and returned, this table is not changed. + */ + public AbstractTable transpose() { + return newInstance(colCount(), rowCount(), (i, j) -> get0(j, i)); + } + } diff --git a/src/main/java/pkovacs/util/data/CharTable.java b/src/main/java/pkovacs/util/data/CharTable.java index 4546dc3..c722940 100644 --- a/src/main/java/pkovacs/util/data/CharTable.java +++ b/src/main/java/pkovacs/util/data/CharTable.java @@ -88,6 +88,11 @@ void set0(int row, int col, Character value) { data[row][col] = value; } + @Override + CharTable newInstance(int rowCount, int colCount, BiFunction function) { + return new CharTable(rowCount, colCount, function); + } + /** * Returns the {@code char[][]} array that backs this table. Changes to the returned array are reflected in the * table, and vice-versa. @@ -160,6 +165,31 @@ public Stream values(int startRow, int startCol, int endRow, int endC return cells(startRow, startCol, endRow, endCol).map(this::get); } + @Override + public CharTable mirrorHorizontally() { + return (CharTable) super.mirrorHorizontally(); + } + + @Override + public CharTable mirrorVertically() { + return (CharTable) super.mirrorVertically(); + } + + @Override + public CharTable rotateRight() { + return (CharTable) super.rotateRight(); + } + + @Override + public CharTable rotateLeft() { + return (CharTable) super.rotateLeft(); + } + + @Override + public CharTable transpose() { + return (CharTable) super.transpose(); + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/main/java/pkovacs/util/data/IntTable.java b/src/main/java/pkovacs/util/data/IntTable.java index 3aa7c62..b47d05e 100644 --- a/src/main/java/pkovacs/util/data/IntTable.java +++ b/src/main/java/pkovacs/util/data/IntTable.java @@ -86,6 +86,11 @@ void set0(int row, int col, Integer value) { data[row][col] = value; } + @Override + IntTable newInstance(int rowCount, int colCount, BiFunction function) { + return new IntTable(rowCount, colCount, function); + } + /** * Returns the {@code int[][]} array that backs this table. Changes to the returned array are reflected in the * table, and vice-versa. @@ -193,6 +198,31 @@ public int max() { return values().max().orElseThrow(); } + @Override + public IntTable mirrorHorizontally() { + return (IntTable) super.mirrorHorizontally(); + } + + @Override + public IntTable mirrorVertically() { + return (IntTable) super.mirrorVertically(); + } + + @Override + public IntTable rotateRight() { + return (IntTable) super.rotateRight(); + } + + @Override + public IntTable rotateLeft() { + return (IntTable) super.rotateLeft(); + } + + @Override + public IntTable transpose() { + return (IntTable) super.transpose(); + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/main/java/pkovacs/util/data/Table.java b/src/main/java/pkovacs/util/data/Table.java index c0a067f..83c70e2 100644 --- a/src/main/java/pkovacs/util/data/Table.java +++ b/src/main/java/pkovacs/util/data/Table.java @@ -84,6 +84,11 @@ void set0(int row, int col, T value) { data[row][col] = value; } + @Override + Table newInstance(int rowCount, int colCount, BiFunction function) { + return new Table(rowCount, colCount, function); + } + /** * Returns the value associated with the specified cell. */ @@ -148,6 +153,31 @@ public Stream values(int startRow, int startCol, int endRow, int endCol) { return cells(startRow, startCol, endRow, endCol).map(this::get); } + @Override + public Table mirrorHorizontally() { + return (Table) super.mirrorHorizontally(); + } + + @Override + public Table mirrorVertically() { + return (Table) super.mirrorVertically(); + } + + @Override + public Table rotateRight() { + return (Table) super.rotateRight(); + } + + @Override + public Table rotateLeft() { + return (Table) super.rotateLeft(); + } + + @Override + public Table transpose() { + return (Table) super.transpose(); + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/test/java/pkovacs/util/data/AbstractTableTest.java b/src/test/java/pkovacs/util/data/AbstractTableTest.java index fcaf4dc..c8e67d6 100644 --- a/src/test/java/pkovacs/util/data/AbstractTableTest.java +++ b/src/test/java/pkovacs/util/data/AbstractTableTest.java @@ -99,6 +99,40 @@ void testCellNeighbors() { table.extendedNeighborCells(new Tile(2, 1)).toList()); } + @Test + void testTransformations() { + var table = createTestTable(3, 4); + var transposed = table.transpose(); + var right = table.rotateRight(); + var left = table.rotateLeft(); + + assertEquals(table.rowCount(), transposed.colCount()); + assertEquals(table.colCount(), transposed.rowCount()); + assertEquals(table.rowCount(), right.colCount()); + assertEquals(table.colCount(), right.rowCount()); + assertEquals(table.rowCount(), left.colCount()); + assertEquals(table.colCount(), left.rowCount()); + + assertNotEquals(transposed, right); + assertNotEquals(transposed, left); + assertNotEquals(right, left); + + assertEquals(table, transposed.transpose()); + assertEquals(table, right.rotateLeft()); + assertEquals(table, left.rotateRight()); + assertEquals(table, right.rotateRight().rotateRight().rotateRight()); + assertEquals(table, left.rotateLeft().rotateLeft().rotateLeft()); + assertEquals(table, right.rotateRight().mirrorVertically().mirrorHorizontally()); + assertEquals(table, left.rotateLeft().mirrorVertically().mirrorHorizontally()); + + assertEquals(right.rotateRight(), left.rotateLeft()); + + assertEquals(transposed, right.mirrorHorizontally()); + assertEquals(transposed, left.mirrorVertically()); + assertEquals(transposed, table.mirrorVertically().rotateRight()); + assertEquals(transposed, table.mirrorHorizontally().rotateLeft()); + } + @Test void testEqualsAndHashCode() { var table1 = createTestTable(3, 4); diff --git a/src/test/java/pkovacs/util/data/IntTableTest.java b/src/test/java/pkovacs/util/data/IntTableTest.java index 1b5aa1c..47b5a43 100644 --- a/src/test/java/pkovacs/util/data/IntTableTest.java +++ b/src/test/java/pkovacs/util/data/IntTableTest.java @@ -108,6 +108,12 @@ void testToString() { table3.set(1, 1, 424242); assertEquals(" 0 -1 2 -3\n -100 424242 -102 103\n 200 -201 202 -203\n", table3.toString()); + + var table4 = createTestTable(3, 4).transpose(); + var table5 = createTestTable(3, 4).rotateRight(); + + assertEquals(" 0 100 200\n 1 101 201\n 2 102 202\n 3 103 203\n", table4.toString()); + assertEquals("200 100 0\n201 101 1\n202 102 2\n203 103 3\n", table5.toString()); } private static void assertContentEquals(int[][] expected, IntTable table) {