Created
March 21, 2016 17:10
-
-
Save ishmaelmakitla/d89d29cb27332606efa8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ishmael.academia.examples.tut.dpc401t; | |
import java.io.BufferedReader; | |
import java.io.FileReader; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* This is a utility class for processing Paint Commands | |
* | |
* @author Ishmael Makitla, | |
* Lecturer - Digital Process Control IV (DPC401T) 2016 | |
* | |
*/ | |
public class PaintRobotCommandProcessor { | |
private static final char DOT = '.'; | |
private static final char HASH = '#'; | |
private static final String SPACE = " "; | |
private static final String DIM = "DIM"; | |
private static final String PAINT_LINE = "PAINT_LINE"; | |
private static final String PAINT_SQUARE = "PAINT_SQUARE"; | |
//this keeps list of commands that produce the output | |
List<String> commands = new ArrayList<String>(); | |
private char[][] mPictureMatrix; | |
public PaintRobotCommandProcessor(char[][] inputMatrix){ | |
this.mPictureMatrix = inputMatrix; | |
} | |
/** | |
* Helper function to process the paint command (update the character-matrix with '.' or '#') | |
* PAINT_SQUARE R C S - paints all cells within the square of (2S + 1) × (2S + 1) dimensions centered at [R , C ] . | |
In particular, the command “PAINT_SQUARE R C 0” paints a single cell [R , C ]: (0+1)x(0+1) = 1 (number of cells) | |
Another example: PAINT_SQUARE 2 3 1 : Centre = [2,3] : ((2x1) +1)((2x1)+1) = (3)x(3) = 9 (number of cells to paint): | |
..###.. | |
..###.. (centre = Row 3 (3-1), Col 4 (4-1)) | |
..###.. | |
* @param paintCommand | |
*/ | |
public void processPaintSquareCommand(int rowIndex, int columnIndex, int s){ | |
int cellNumbers = ((s*2)+1)*((s*2)+1); | |
int cellsPerSide = (int)Math.sqrt((double)cellNumbers)/2; | |
//do the actual painting by changing the characters in the array that are within the specified square | |
if(cellNumbers == 1){ | |
//this is just the printing of one cell - so only one character needs changing | |
mPictureMatrix[rowIndex][columnIndex] = HASH; | |
commands.add("PAINT_SQUARE"+" "+rowIndex+" "+columnIndex+" "+s); | |
} | |
else if (cellsPerSide > 1){ | |
//this is a square bigger than 3x3 | |
commands.add("PAINT_SQUARE"+" "+rowIndex+" "+columnIndex+" "+s); | |
printBigSquare(rowIndex, columnIndex, s); | |
} | |
else{ | |
//the cellNumber has to be indivisible by 2 (otherwise we cannot have a centre) | |
if((cellNumbers%2 == 0)){ | |
System.out.println("Invalid Command for Square Painting ... Number of Cells MUST NOT be divisible by 2. MUST be Odd!! "); | |
return; | |
} | |
//First we paint the centre - easiest | |
mPictureMatrix[rowIndex][columnIndex] = HASH; | |
//here we are painting a number of cells within a square, so we calculate the square-root of the cellNumbers - | |
//we then work out which cells are within the square | |
//we compute the length of each side of the square - by calculating the square-root (this is the number of cells making each side) | |
int sideLength = (int)Math.sqrt((double)cellNumbers); | |
//number of cells on each side of the centre | |
int cellsToTheEdgeOfSquare = sideLength/2; | |
int index = 1; | |
for(int x=0; x < cellsToTheEdgeOfSquare; x++){ | |
//drawing a cross from the center to the four sides | |
//up | |
mPictureMatrix[rowIndex-index][columnIndex] = HASH; | |
//up-and-right | |
mPictureMatrix[rowIndex-index][columnIndex+index] = HASH; | |
//up-and-left | |
mPictureMatrix[rowIndex-index][columnIndex-index] = HASH; | |
//left | |
mPictureMatrix[rowIndex][columnIndex-index] = HASH; | |
//right | |
mPictureMatrix[rowIndex][columnIndex+index] = HASH; | |
//down | |
mPictureMatrix[rowIndex+index][columnIndex] = HASH; | |
//down-and-right | |
mPictureMatrix[rowIndex+index][columnIndex+index] = HASH; | |
//down-and-left | |
mPictureMatrix[rowIndex+index][columnIndex-index] = HASH; | |
index +=1; | |
} | |
//add the command to the command-list | |
//Command-String :: PAINT_SQUARE 5 65 1 | |
commands.add("PAINT_SQUARE"+" "+rowIndex+" "+columnIndex+" "+s); | |
} | |
} | |
/** | |
* For printing square bigger than S=1 | |
*/ | |
private void printBigSquare(int rowIndex, int columnIndex, int s){ | |
//draw lines of length-x starting from top-left corder of the desired square | |
//we compute the length of each side of the square - by calculating the square-root (this is the number of cells making each side) | |
int cellNumbers = ((s*2)+1)*((s*2)+1); | |
int sideLength = (int)Math.sqrt((double)cellNumbers); | |
//sideLength is the length of each line we will draw to make our square | |
//work out the coordinates of the first and last lines | |
//first we need to know how many cells to the edge of the squre | |
int cellsToTheEdgeOfSquare = sideLength/2; | |
int firstColumnIndex = columnIndex - cellsToTheEdgeOfSquare; | |
int lastColumnIndexEnd = columnIndex + cellsToTheEdgeOfSquare+1; //we add 1 to INCLUDE the last column | |
int firstRowIndex = rowIndex - cellsToTheEdgeOfSquare; | |
int lastRowIndex = rowIndex + cellsToTheEdgeOfSquare+1; //we add 1 to INCLUDE the last row | |
//loop from the start-cell of the square to the end, and move to the next row | |
for(int row=firstRowIndex; row < lastRowIndex; row++){ | |
for( int col=firstColumnIndex; col < lastColumnIndexEnd; col++){ | |
mPictureMatrix[row][col] = HASH; | |
} | |
} | |
} | |
/** | |
* PAINT_LINE R1 C1 R2 C2 - paints all cells in a horizontal or vertical run between [R1, C1] (start) and [R2,C2] (end). | |
* That is, at least one of the two has to be true: R1 = R2 or/and C1 = C2 . | |
*/ | |
public void processPaintLineCommand(int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex){ | |
//since this is a line, either same column or same row - otherwise the command is invalid | |
//E.g line on row-0 starts at 0,0 ends at 0,5 (horizontal), or starts at 0,0 ends at 5,0 (vertical) | |
if( (startRowIndex) != endRowIndex && (startColumnIndex != endColumnIndex)){ | |
System.out.println("Invalid Command for Line Painting ... "); | |
return; | |
} | |
boolean isHorizontal = (startRowIndex == endRowIndex ? true : false); | |
//draw the line of length | |
if(isHorizontal){ | |
for(int x= startColumnIndex; x < endColumnIndex+1; x++){ | |
mPictureMatrix[startRowIndex][x] = HASH; | |
} | |
} | |
else{ | |
for(int x= startRowIndex; x < endRowIndex+1; x++){ | |
mPictureMatrix[x][startColumnIndex] = HASH; | |
} | |
} | |
//add the Paint-Line command of the form: PAINT_LINE 0 4 3 4 | |
commands.add("PAINT_LINE"+" "+startRowIndex+" "+startColumnIndex+" "+endRowIndex+" "+endColumnIndex); | |
} | |
/** | |
* Method to process the ERASE command: it basically puts '.' at the specified cell of the 2-D array; | |
* ERASE_CELL R C - clears the cell [R,C]. | |
* | |
*/ | |
public void processEraseCellCommand(int rowIndex, int columnIndex){ | |
mPictureMatrix[rowIndex][columnIndex] = DOT; | |
//add Erase Cell command of the form: ERASE_CELL 8 35 | |
commands.add("ERASE_CELL"+" "+rowIndex+" "+columnIndex); | |
} | |
public String showAsString(){ | |
return asStringPictureMatrix(mPictureMatrix); | |
} | |
/** | |
* Convenience method to create a picture-matrix from dimensions | |
*/ | |
public static char[][] createPictureMatrix(final int rows, final int columns){ | |
char[][] pictureMatrix = new char[rows][columns]; | |
for(int x=0; x< rows; x++){ | |
for (int y=0; y <columns; y++){ | |
pictureMatrix[x][y] = DOT; | |
} | |
} | |
return pictureMatrix; | |
} | |
/** | |
* Convenience method that converts the array onto a matrix-string. It is used to generate the output | |
* similar to those submitted by Google for Hash Code Practice Challenge; | |
* | |
*/ | |
public static String asStringPictureMatrix(final char[][] pictureMatrix){ | |
int rows = pictureMatrix.length; | |
int columns = pictureMatrix[0].length; | |
String outputMatrix = ""; | |
StringBuilder stringBuilder = new StringBuilder(); | |
for(int x=0; x< rows; x++){ | |
for (int y=0; y <columns; y++){ | |
stringBuilder.append(pictureMatrix[x][y]); | |
//end of row? | |
if(y+1 >= columns){ | |
stringBuilder.append('\n'); | |
} | |
} | |
} | |
outputMatrix = stringBuilder.toString(); | |
return outputMatrix; | |
} | |
/** | |
* This function is used to create a file of commands used to produce the desired outcomes | |
*/ | |
public void createCommandsFile(){ | |
try { | |
FileWriter fw = new FileWriter("commands.txt"); | |
for (int x = 0; x < commands.size(); x++) { | |
fw.write(commands.get(x)); | |
fw.write('\n'); | |
} | |
fw.close(); | |
} catch (IOException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* This utility function is used to read commands from the file and process them in the sequence they appear in the commands-file. | |
* The first line of the file should be the directive for the dimentions DIM Rows Columns | |
* The expected line format is: | |
* PAINT_SQUARE 18 69 5 | |
* PAINT_LINE 20 52 20 63 | |
*/ | |
public static void processCommandFile(String commandFilePath) throws IllegalArgumentException{ | |
int dimRows = 0; | |
int dimColumns = 0; | |
PaintRobotCommandProcessor processorInstance = null; | |
try{ | |
FileReader fileReaderr = new FileReader(commandFilePath); | |
BufferedReader bufferedReader = new BufferedReader(fileReaderr); | |
String commandLine; | |
int lineCounter = 0; | |
while ((commandLine = bufferedReader.readLine()) != null){ | |
//if this is the first line, then it specified the dimensions - these will be used to make sure | |
//the painted cells are within range | |
if(lineCounter == 0){ | |
//the first word must be DIM, followed by rows and then columns - | |
String[] dimensionWords = commandLine.split(SPACE); | |
if(dimensionWords.length < 3){ | |
throw new IllegalArgumentException("Invalid Format for dimension directive. Should be three words: DIM Num Num"); | |
} | |
if(dimensionWords[0].trim().equalsIgnoreCase(DIM)){ | |
dimRows = Integer.parseInt(dimensionWords[1]); | |
dimColumns = Integer.parseInt(dimensionWords[2]); | |
char[][] inputMatrix = createPictureMatrix(dimRows, dimColumns); | |
processorInstance = new PaintRobotCommandProcessor(inputMatrix); | |
} | |
else{ | |
//invalid entry in the file | |
throw new IllegalArgumentException("Invalid Command In the File. Expeceted dimension directive DIM"); | |
} | |
} | |
else{ | |
//this is the subsequent command line | |
String[] paintCommandWords = commandLine.split(SPACE); | |
if(paintCommandWords.length < 4 || paintCommandWords.length > 5){ | |
throw new IllegalArgumentException("Invalid Format for Paint Command. Should be Four or Five Words"); | |
} | |
String commandType = paintCommandWords[0]; | |
if(commandType!= null && commandType.trim().equalsIgnoreCase(PAINT_LINE)){ | |
//command format: PAINT_LINE 20 52 20 63 | |
int startCellRow = Integer.parseInt(paintCommandWords[1]); | |
int startCellColumn = Integer.parseInt(paintCommandWords[2]); | |
int endCellRow = Integer.parseInt(paintCommandWords[3]); | |
int endCellColumn = Integer.parseInt(paintCommandWords[4]); | |
//For simulation, we call the processPaintLineCommand | |
processorInstance.processPaintLineCommand(startCellRow, startCellColumn, endCellRow, endCellColumn); | |
//ideally, at this point you should send the command to your paint-robot | |
} | |
else if (commandType!= null && commandType.trim().equalsIgnoreCase(PAINT_SQUARE)){ | |
//command format: PAINT_SQUARE 18 69 5 | |
int squareCentreCellRow = Integer.parseInt(paintCommandWords[1]); | |
int squareCentreCellColumn = Integer.parseInt(paintCommandWords[2]); | |
int sideLength = Integer.parseInt(paintCommandWords[3]); | |
//For simulation, we call the processPaintSquareCommand on our simulator | |
processorInstance.processPaintSquareCommand(squareCentreCellRow, squareCentreCellColumn, sideLength); | |
} | |
} | |
lineCounter +=1; | |
} | |
//if we did create the processor instance, we can try printing it out | |
if(processorInstance != null){ | |
System.out.println(processorInstance.showAsString()); | |
} | |
} | |
catch(Exception commandProcessingException){ | |
throw new IllegalArgumentException("There was a problem processing Commands File. Message : "+commandProcessingException.getLocalizedMessage()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here is an example of the content of the command.txt file:
DIM 20 20
PAINT_SQUARE 10 10 3
PAINT_LINE 0 0 0 19
PAINT_LINE 1 0 1 19
PAINT_LINE 10 17 19 17
PAINT_LINE 10 19 19 19
Copy and paste the following into a file called commands.txt in the working directory of your project - then you can use the command-processor as illustrated in the comment above.