Add a second page with the solution to the PDF.
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is failing
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	continuous-integration/drone/push Build is failing
				
			This commit is contained in:
		
							parent
							
								
									74441c91cc
								
							
						
					
					
						commit
						911aa35577
					
				
					 2 changed files with 82 additions and 22 deletions
				
			
		|  | @ -13,7 +13,9 @@ public class Labyrinth { | |||
|     private final int width; | ||||
|     @Getter | ||||
|     private final int height; | ||||
|     @Getter | ||||
|     private final Position start; | ||||
|     @Getter | ||||
|     private final Position end; | ||||
| 
 | ||||
|     public Labyrinth(final int width, final int height) { | ||||
|  |  | |||
|  | @ -5,12 +5,16 @@ import org.apache.pdfbox.pdmodel.PDDocument; | |||
| import org.apache.pdfbox.pdmodel.PDPage; | ||||
| import org.apache.pdfbox.pdmodel.PDPageContentStream; | ||||
| import org.apache.pdfbox.pdmodel.common.PDRectangle; | ||||
| import org.jetbrains.annotations.Nullable; | ||||
| 
 | ||||
| import java.awt.*; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| public class PDFRenderer implements Renderer<byte[]> { | ||||
|     private static final float MARGIN = 10; | ||||
|     private static final float SCALE = 10; | ||||
| 
 | ||||
|     private PDFRenderer() { | ||||
| 
 | ||||
|     } | ||||
|  | @ -20,13 +24,15 @@ public class PDFRenderer implements Renderer<byte[]> { | |||
|         return new PDFRenderer(); | ||||
|     } | ||||
| 
 | ||||
|     private static boolean isValid(@NonNull final Position position) { | ||||
|         return position.getX() >= 0 && position.getY() >= 0; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @NonNull | ||||
|     public byte[] render(@NonNull final Labyrinth labyrinth) { | ||||
|         final float scale = 10; | ||||
|         final float margin = 5; | ||||
|         final float pageWidth = labyrinth.getWidth() * scale + 2 * margin; | ||||
|         final float pageHeight = labyrinth.getHeight() * scale + 2 * margin; | ||||
|         final float pageWidth = labyrinth.getWidth() * SCALE + 2 * MARGIN; | ||||
|         final float pageHeight = labyrinth.getHeight() * SCALE + 2 * MARGIN; | ||||
| 
 | ||||
|         final PDDocument pdDocument = new PDDocument(); | ||||
|         final PDPage page = new PDPage(new PDRectangle(pageWidth, pageHeight)); | ||||
|  | @ -37,8 +43,22 @@ public class PDFRenderer implements Renderer<byte[]> { | |||
|             pdPageContentStream.setLineWidth(1.0f); | ||||
|             pdPageContentStream.setStrokingColor(Color.BLACK); | ||||
|             pdPageContentStream.setNonStrokingColor(Color.BLACK); | ||||
|             this.drawHorizonzalLines(labyrinth, pdPageContentStream, margin, scale); | ||||
|             this.drawVerticalLines(labyrinth, pdPageContentStream, margin, scale); | ||||
|             this.drawHorizonzalLines(labyrinth, pdPageContentStream); | ||||
|             this.drawVerticalLines(labyrinth, pdPageContentStream); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         final PDPage solution = new PDPage(new PDRectangle(pageWidth, pageHeight)); | ||||
|         pdDocument.addPage(solution); | ||||
|         try (PDPageContentStream pdPageContentStream = new PDPageContentStream(pdDocument, solution)) { | ||||
|             pdPageContentStream.setLineCapStyle(BasicStroke.CAP_ROUND); | ||||
|             pdPageContentStream.setLineJoinStyle(BasicStroke.JOIN_MITER); | ||||
|             pdPageContentStream.setLineWidth(1.0f); | ||||
|             pdPageContentStream.setStrokingColor(Color.BLACK); | ||||
|             pdPageContentStream.setNonStrokingColor(Color.BLACK); | ||||
|             this.drawHorizonzalLines(labyrinth, pdPageContentStream); | ||||
|             this.drawVerticalLines(labyrinth, pdPageContentStream); | ||||
|             this.drawSolution(labyrinth, pdPageContentStream); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|  | @ -52,28 +72,29 @@ public class PDFRenderer implements Renderer<byte[]> { | |||
|         return output.toByteArray(); | ||||
|     } | ||||
| 
 | ||||
|     private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth, @NonNull final PDPageContentStream pdPageContentStream, final float margin, final float scale) throws IOException { | ||||
|     private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth, | ||||
|                                      @NonNull final PDPageContentStream pdPageContentStream) throws IOException { | ||||
|         // PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required. | ||||
|         final float labyrinthHeight = labyrinth.getHeight() * scale; | ||||
|         final float labyrinthHeight = labyrinth.getHeight() * SCALE; | ||||
|         for (int y = 0; y < labyrinth.getHeight(); y++) { | ||||
|             boolean isPainting = false; | ||||
|             for (int x = 0; x < labyrinth.getWidth(); x++) { | ||||
|                 final Tile currentTile = labyrinth.getTileAt(x, y); | ||||
|                 if (currentTile.hasWallAt(Direction.TOP)) { | ||||
|                     if (!isPainting) { | ||||
|                         pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin); | ||||
|                         pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||
|                         isPainting = true; | ||||
|                     } | ||||
|                 } else { | ||||
|                     if (isPainting) { | ||||
|                         pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin); | ||||
|                         pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||
|                         pdPageContentStream.stroke(); | ||||
|                         isPainting = false; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if (isPainting) { | ||||
|                 pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, labyrinthHeight - y * scale + margin); | ||||
|                 pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||
|                 pdPageContentStream.stroke(); | ||||
|             } | ||||
|         } | ||||
|  | @ -83,45 +104,46 @@ public class PDFRenderer implements Renderer<byte[]> { | |||
|             final Tile currentTile = labyrinth.getTileAt(x, y - 1); | ||||
|             if (currentTile.hasWallAt(Direction.BOTTOM)) { | ||||
|                 if (!isPainting) { | ||||
|                     pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin); | ||||
|                     pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||
|                     isPainting = true; | ||||
|                 } | ||||
|             } else { | ||||
|                 if (isPainting) { | ||||
|                     pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin); | ||||
|                     pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||
|                     pdPageContentStream.stroke(); | ||||
|                     isPainting = false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (isPainting) { | ||||
|             pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, labyrinthHeight - labyrinth.getHeight() * scale + margin); | ||||
|             pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN); | ||||
|             pdPageContentStream.stroke(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void drawVerticalLines(@NonNull final Labyrinth labyrinth, @NonNull final PDPageContentStream pdPageContentStream, final float margin, final float scale) throws IOException { | ||||
|     private void drawVerticalLines(@NonNull final Labyrinth labyrinth, | ||||
|                                    @NonNull final PDPageContentStream pdPageContentStream) throws IOException { | ||||
|         // PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required. | ||||
|         final float labyrinthHeight = labyrinth.getHeight() * scale; | ||||
|         final float labyrinthHeight = labyrinth.getHeight() * SCALE; | ||||
|         for (int x = 0; x < labyrinth.getWidth(); x++) { | ||||
|             boolean isPainting = false; | ||||
|             for (int y = 0; y < labyrinth.getHeight(); y++) { | ||||
|                 final Tile currentTile = labyrinth.getTileAt(x, y); | ||||
|                 if (currentTile.hasWallAt(Direction.LEFT)) { | ||||
|                     if (!isPainting) { | ||||
|                         pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin); | ||||
|                         pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||
|                         isPainting = true; | ||||
|                     } | ||||
|                 } else { | ||||
|                     if (isPainting) { | ||||
|                         pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin); | ||||
|                         pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||
|                         pdPageContentStream.stroke(); | ||||
|                         isPainting = false; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if (isPainting) { | ||||
|                 pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - labyrinth.getHeight() * scale + margin); | ||||
|                 pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN); | ||||
|                 pdPageContentStream.stroke(); | ||||
|             } | ||||
|         } | ||||
|  | @ -131,20 +153,56 @@ public class PDFRenderer implements Renderer<byte[]> { | |||
|             final Tile currentTile = labyrinth.getTileAt(x - 1, y); | ||||
|             if (currentTile.hasWallAt(Direction.RIGHT)) { | ||||
|                 if (!isPainting) { | ||||
|                     pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin); | ||||
|                     pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||
|                     isPainting = true; | ||||
|                 } | ||||
|             } else { | ||||
|                 if (isPainting) { | ||||
|                     pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin); | ||||
|                     pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||
|                     pdPageContentStream.stroke(); | ||||
|                     isPainting = false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (isPainting) { | ||||
|             pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, labyrinthHeight - labyrinth.getHeight() * scale + margin); | ||||
|             pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN); | ||||
|             pdPageContentStream.stroke(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void drawSolution(@NonNull final Labyrinth labyrinth, | ||||
|                               @NonNull final PDPageContentStream pdPageContentStream) throws IOException { | ||||
|         // Draw the solution in red | ||||
|         pdPageContentStream.setStrokingColor(Color.RED); | ||||
|         // PDF has the origin in the lower left corner. We want it in the upper left corner, hence some magic is required. | ||||
|         final float labyrinthHeight = labyrinth.getHeight() * SCALE; | ||||
|         final Position end = labyrinth.getEnd(); | ||||
|         Position currentPosition = labyrinth.getStart(); | ||||
|         Position previousPosition = null; | ||||
|         pdPageContentStream.moveTo(MARGIN + currentPosition.getX() * SCALE + SCALE / 2, MARGIN + labyrinthHeight - (currentPosition.getY() * SCALE + SCALE / 2)); | ||||
|         do { | ||||
|             Position newCurrent = this.findNextSolutionPosition(labyrinth, previousPosition, currentPosition); | ||||
|             previousPosition = currentPosition; | ||||
|             currentPosition = newCurrent; | ||||
|             pdPageContentStream.lineTo(MARGIN + currentPosition.getX() * SCALE + SCALE / 2, MARGIN + labyrinthHeight - (currentPosition.getY() * SCALE + SCALE / 2)); | ||||
|         } while (!currentPosition.equals(end)); | ||||
|         pdPageContentStream.stroke(); | ||||
|     } | ||||
| 
 | ||||
|     private Position findNextSolutionPosition(@NonNull final Labyrinth labyrinth, @Nullable final Position previousPosition, @NonNull final Position currentPosition) { | ||||
|         final Tile currentTile = labyrinth.getTileAt(currentPosition); | ||||
|         for (final Direction direction : Direction.values()) { | ||||
|             if (!currentTile.hasWallAt(direction)) { | ||||
|                 final Position position = direction.translate(currentPosition); | ||||
|                 if (position.equals(previousPosition) || !isValid(position)) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (labyrinth.getTileAt(position).isSolution()) { | ||||
|                     return position; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // We *SHOULD* never get here. ... famous last words ... | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue