mirror of
https://github.com/AppleCommander/bastools.git
synced 2024-06-26 10:29:28 +00:00
Starting shape table generation. #16.
This commit is contained in:
parent
ed665de0a6
commit
47ea9e41de
|
@ -44,6 +44,35 @@ public class BitmapShape implements Shape {
|
|||
grid.add(newRow(getWidth()));
|
||||
}
|
||||
|
||||
public void appendBitmapRow(String line) {
|
||||
line = line.trim();
|
||||
List<Boolean> row = new ArrayList<>();
|
||||
Runnable setOrigin = () -> {
|
||||
// Share origin logic for '+' and '*'
|
||||
origin.x = row.size();
|
||||
origin.y = grid.size();
|
||||
};
|
||||
for (char pixel : line.toCharArray()) {
|
||||
switch (pixel) {
|
||||
case '+':
|
||||
setOrigin.run();
|
||||
// fall through to '.'
|
||||
case '.':
|
||||
row.add(Boolean.FALSE);
|
||||
break;
|
||||
case '*':
|
||||
setOrigin.run();
|
||||
// fall through to 'x'
|
||||
case 'x':
|
||||
row.add(Boolean.TRUE);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unexpected bitmap pixel type: " + pixel);
|
||||
}
|
||||
}
|
||||
grid.add(row);
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return grid.size();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
package io.github.applecommander.bastools.api.shapes;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ShapeGenerator {
|
||||
public static ShapeTable generate(Reader sourceReader) throws IOException {
|
||||
Objects.requireNonNull(sourceReader);
|
||||
|
||||
ShapeTable st = new ShapeTable();
|
||||
LineNumberReader reader = new LineNumberReader(sourceReader);
|
||||
String line = reader.readLine();
|
||||
Consumer<String> shapeConsumer = null;
|
||||
while (line != null) {
|
||||
line = reader.readLine();
|
||||
if (line == null) break;
|
||||
|
||||
int comment = line.indexOf(';');
|
||||
if (comment > -1) line = line.substring(0, comment);
|
||||
line = line.trim();
|
||||
if (line.length() == 0) continue;
|
||||
|
||||
switch (line.toLowerCase()) {
|
||||
case ".short":
|
||||
VectorShape shortShape = new VectorShape();
|
||||
st.shapes.add(shortShape);
|
||||
shapeConsumer = shortShape::appendShortCommands;
|
||||
break;
|
||||
case ".long":
|
||||
VectorShape longShape = new VectorShape();
|
||||
st.shapes.add(longShape);
|
||||
shapeConsumer = longShape::appendLongCommands;
|
||||
break;
|
||||
case ".bitmap":
|
||||
BitmapShape bitmapShape = new BitmapShape();
|
||||
st.shapes.add(bitmapShape);
|
||||
shapeConsumer = bitmapShape::appendBitmapRow;
|
||||
break;
|
||||
default:
|
||||
if (shapeConsumer != null) {
|
||||
try {
|
||||
shapeConsumer.accept(line);
|
||||
} catch (Throwable t) {
|
||||
String message = String.format("Error at line #%d - %s", reader.getLineNumber(), t.getMessage());
|
||||
throw new IOException(message, t);
|
||||
}
|
||||
} else {
|
||||
throw new IOException("Unexpected command: " + line);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return st;
|
||||
}
|
||||
public static ShapeTable generate(InputStream inputStream) throws IOException {
|
||||
Objects.requireNonNull(inputStream);
|
||||
try (Reader reader = new InputStreamReader(inputStream)) {
|
||||
return generate(reader);
|
||||
}
|
||||
}
|
||||
public static ShapeTable generate(File file) throws IOException {
|
||||
Objects.requireNonNull(file);
|
||||
try (Reader reader = new FileReader(file)) {
|
||||
return generate(reader);
|
||||
}
|
||||
}
|
||||
public static ShapeTable generate(Path path) throws IOException {
|
||||
Objects.requireNonNull(path);
|
||||
return generate(path.toFile());
|
||||
}
|
||||
}
|
|
@ -2,8 +2,11 @@ package io.github.applecommander.bastools.api.shapes;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
|
||||
public class VectorShape implements Shape {
|
||||
public static VectorShape from(ByteBuffer buf) {
|
||||
|
@ -48,6 +51,52 @@ public class VectorShape implements Shape {
|
|||
return this;
|
||||
}
|
||||
|
||||
public void appendShortCommands(String line) {
|
||||
for (char cmd : line.trim().toCharArray()) {
|
||||
switch (cmd) {
|
||||
case 'u': moveUp(); break;
|
||||
case 'd': moveDown(); break;
|
||||
case 'l': moveLeft(); break;
|
||||
case 'r': moveRight(); break;
|
||||
case 'U': plotUp(); break;
|
||||
case 'D': plotDown(); break;
|
||||
case 'L': plotLeft(); break;
|
||||
case 'R': plotRight(); break;
|
||||
default:
|
||||
if (Character.isWhitespace(cmd)) {
|
||||
// whitespace is allowed
|
||||
continue;
|
||||
}
|
||||
throw new RuntimeException("Unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void appendLongCommands(String line) {
|
||||
Queue<String> tokens = new LinkedList<>(Arrays.asList(line.split("\\s+")));
|
||||
while (!tokens.isEmpty()) {
|
||||
String command = tokens.remove();
|
||||
int count = 1;
|
||||
String checkNumber = tokens.peek();
|
||||
if (checkNumber != null && checkNumber.matches("\\d+")) count = Integer.parseInt(tokens.remove());
|
||||
|
||||
for (int i=0; i<count; i++) {
|
||||
switch (command.toLowerCase()) {
|
||||
case "moveup": moveUp(); break;
|
||||
case "movedown": moveDown(); break;
|
||||
case "moveleft": moveLeft(); break;
|
||||
case "moveright": moveRight(); break;
|
||||
case "plotup": plotUp(); break;
|
||||
case "plotdown": plotDown(); break;
|
||||
case "plotleft": plotLeft(); break;
|
||||
case "plotright": plotRight(); break;
|
||||
default:
|
||||
throw new RuntimeException("Unknown command: " + command);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return vectors.isEmpty();
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package io.github.applecommander.bastools.api.shapes;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ShapeGeneratorTest {
|
||||
@Test
|
||||
public void generateBoxShortformTest() throws IOException {
|
||||
ShapeTable st = ShapeGenerator.generate(getClass().getResourceAsStream("/box-shortform.st"));
|
||||
assertShapeIsBox(st);
|
||||
assertShapeBoxVectors(st);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateBoxLongformTest() throws IOException {
|
||||
ShapeTable st = ShapeGenerator.generate(getClass().getResourceAsStream("/box-longform.st"));
|
||||
assertShapeIsBox(st);
|
||||
assertShapeBoxVectors(st);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateBoxBitmapTest() throws IOException {
|
||||
ShapeTable st = ShapeGenerator.generate(getClass().getResourceAsStream("/box-bitmap.st"));
|
||||
assertShapeIsBox(st);
|
||||
// Unable to test vectors for bitmaps
|
||||
}
|
||||
|
||||
public void assertShapeIsBox(ShapeTable st) throws IOException {
|
||||
assertNotNull(st);
|
||||
assertEquals(1, st.shapes.size());
|
||||
|
||||
final String expected = "+-----+\n"
|
||||
+ "|.XXX.|\n"
|
||||
+ "|X...X|\n"
|
||||
+ "|X.+.X|\n"
|
||||
+ "|X...X|\n"
|
||||
+ "|.XXX.|\n"
|
||||
+ "+-----+\n";
|
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
ShapeExporter exp = ShapeExporter.text().asciiTextBorder().build();
|
||||
exp.export(st.shapes.get(0), outputStream);
|
||||
String actual = new String(outputStream.toByteArray());
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
public void assertShapeBoxVectors(ShapeTable st) {
|
||||
assertNotNull(st);
|
||||
assertEquals(1, st.shapes.size());
|
||||
|
||||
VectorShape expected = new VectorShape()
|
||||
.moveDown().moveDown()
|
||||
.plotLeft().plotLeft()
|
||||
.moveUp().plotUp().plotUp().plotUp()
|
||||
.moveRight().plotRight().plotRight().plotRight()
|
||||
.moveDown().plotDown().plotDown().plotDown()
|
||||
.moveLeft().plotLeft();
|
||||
|
||||
Shape s = st.shapes.get(0);
|
||||
assertNotNull(s);
|
||||
assertEquals(expected.vectors, s.toVector().vectors);
|
||||
}
|
||||
}
|
16
api/src/test/resources/box-bitmap.st
Normal file
16
api/src/test/resources/box-bitmap.st
Normal file
|
@ -0,0 +1,16 @@
|
|||
; A bitmap that defines a box as given by Applesoft BASIC Programmer's Reference Manual
|
||||
; The bitmap is transformed into a vector by BitmapShape#toVector.
|
||||
|
||||
; Notes:
|
||||
; x = plot
|
||||
; . = unplotted; used to clarify image regions
|
||||
; + = origin, no plot (assumed to be upper-left if unspecified)
|
||||
; * = origin. plot
|
||||
; whitespace is ignored
|
||||
|
||||
.bitmap
|
||||
.xxx.
|
||||
x...x
|
||||
x.+.x
|
||||
x...x
|
||||
.xxx.
|
20
api/src/test/resources/box-longform.st
Normal file
20
api/src/test/resources/box-longform.st
Normal file
|
@ -0,0 +1,20 @@
|
|||
; A vector box as given by Applesoft BASIC Programmer's Reference Manual
|
||||
|
||||
; Notes:
|
||||
; move[up|down|left|right] = move vector
|
||||
; plot[up|down|left|right] = plot vector
|
||||
; whitespace is ignored
|
||||
; case insensitive
|
||||
|
||||
.long
|
||||
movedown 2
|
||||
plotleft 2
|
||||
moveup
|
||||
plotup 3
|
||||
moveright
|
||||
plotright 3
|
||||
movedown
|
||||
plotdown 3
|
||||
moveleft
|
||||
plotleft
|
||||
|
15
api/src/test/resources/box-shortform.st
Normal file
15
api/src/test/resources/box-shortform.st
Normal file
|
@ -0,0 +1,15 @@
|
|||
; A vector box as given by Applesoft BASIC Programmer's Reference Manual
|
||||
|
||||
; Notes:
|
||||
; udlr = move vector
|
||||
; UDLR = plot vector
|
||||
; whitespace is ignored
|
||||
; case sensitive
|
||||
|
||||
.short
|
||||
dd
|
||||
LL
|
||||
uUUU
|
||||
rRRR
|
||||
dDDD
|
||||
lL
|
Loading…
Reference in New Issue
Block a user