Starting shape table generation. #16.

This commit is contained in:
Rob Greene 2018-06-19 15:27:19 -05:00
parent ed665de0a6
commit 47ea9e41de
7 changed files with 277 additions and 0 deletions

View File

@ -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();
}

View File

@ -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());
}
}

View File

@ -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();

View File

@ -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);
}
}

View 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.

View 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

View 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