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; |     private final int width; | ||||||
|     @Getter |     @Getter | ||||||
|     private final int height; |     private final int height; | ||||||
|  |     @Getter | ||||||
|     private final Position start; |     private final Position start; | ||||||
|  |     @Getter | ||||||
|     private final Position end; |     private final Position end; | ||||||
| 
 | 
 | ||||||
|     public Labyrinth(final int width, final int height) { |     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.PDPage; | ||||||
| import org.apache.pdfbox.pdmodel.PDPageContentStream; | import org.apache.pdfbox.pdmodel.PDPageContentStream; | ||||||
| import org.apache.pdfbox.pdmodel.common.PDRectangle; | import org.apache.pdfbox.pdmodel.common.PDRectangle; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
| import java.awt.*; | import java.awt.*; | ||||||
| import java.io.ByteArrayOutputStream; | import java.io.ByteArrayOutputStream; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| 
 | 
 | ||||||
| public class PDFRenderer implements Renderer<byte[]> { | public class PDFRenderer implements Renderer<byte[]> { | ||||||
|  |     private static final float MARGIN = 10; | ||||||
|  |     private static final float SCALE = 10; | ||||||
|  | 
 | ||||||
|     private PDFRenderer() { |     private PDFRenderer() { | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  | @ -20,13 +24,15 @@ public class PDFRenderer implements Renderer<byte[]> { | ||||||
|         return new PDFRenderer(); |         return new PDFRenderer(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private static boolean isValid(@NonNull final Position position) { | ||||||
|  |         return position.getX() >= 0 && position.getY() >= 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     @NonNull |     @NonNull | ||||||
|     public byte[] render(@NonNull final Labyrinth labyrinth) { |     public byte[] render(@NonNull final Labyrinth labyrinth) { | ||||||
|         final float scale = 10; |         final float pageWidth = labyrinth.getWidth() * SCALE + 2 * MARGIN; | ||||||
|         final float margin = 5; |         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 PDDocument pdDocument = new PDDocument(); | ||||||
|         final PDPage page = new PDPage(new PDRectangle(pageWidth, pageHeight)); |         final PDPage page = new PDPage(new PDRectangle(pageWidth, pageHeight)); | ||||||
|  | @ -37,8 +43,22 @@ public class PDFRenderer implements Renderer<byte[]> { | ||||||
|             pdPageContentStream.setLineWidth(1.0f); |             pdPageContentStream.setLineWidth(1.0f); | ||||||
|             pdPageContentStream.setStrokingColor(Color.BLACK); |             pdPageContentStream.setStrokingColor(Color.BLACK); | ||||||
|             pdPageContentStream.setNonStrokingColor(Color.BLACK); |             pdPageContentStream.setNonStrokingColor(Color.BLACK); | ||||||
|             this.drawHorizonzalLines(labyrinth, pdPageContentStream, margin, scale); |             this.drawHorizonzalLines(labyrinth, pdPageContentStream); | ||||||
|             this.drawVerticalLines(labyrinth, pdPageContentStream, margin, scale); |             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) { |         } catch (IOException e) { | ||||||
|             e.printStackTrace(); |             e.printStackTrace(); | ||||||
|         } |         } | ||||||
|  | @ -52,28 +72,29 @@ public class PDFRenderer implements Renderer<byte[]> { | ||||||
|         return output.toByteArray(); |         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. |         // 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++) { |         for (int y = 0; y < labyrinth.getHeight(); y++) { | ||||||
|             boolean isPainting = false; |             boolean isPainting = false; | ||||||
|             for (int x = 0; x < labyrinth.getWidth(); x++) { |             for (int x = 0; x < labyrinth.getWidth(); x++) { | ||||||
|                 final Tile currentTile = labyrinth.getTileAt(x, y); |                 final Tile currentTile = labyrinth.getTileAt(x, y); | ||||||
|                 if (currentTile.hasWallAt(Direction.TOP)) { |                 if (currentTile.hasWallAt(Direction.TOP)) { | ||||||
|                     if (!isPainting) { |                     if (!isPainting) { | ||||||
|                         pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin); |                         pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||||
|                         isPainting = true; |                         isPainting = true; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     if (isPainting) { |                     if (isPainting) { | ||||||
|                         pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin); |                         pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||||
|                         pdPageContentStream.stroke(); |                         pdPageContentStream.stroke(); | ||||||
|                         isPainting = false; |                         isPainting = false; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if (isPainting) { |             if (isPainting) { | ||||||
|                 pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, labyrinthHeight - y * scale + margin); |                 pdPageContentStream.lineTo(labyrinth.getWidth() * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||||
|                 pdPageContentStream.stroke(); |                 pdPageContentStream.stroke(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -83,45 +104,46 @@ public class PDFRenderer implements Renderer<byte[]> { | ||||||
|             final Tile currentTile = labyrinth.getTileAt(x, y - 1); |             final Tile currentTile = labyrinth.getTileAt(x, y - 1); | ||||||
|             if (currentTile.hasWallAt(Direction.BOTTOM)) { |             if (currentTile.hasWallAt(Direction.BOTTOM)) { | ||||||
|                 if (!isPainting) { |                 if (!isPainting) { | ||||||
|                     pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin); |                     pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||||
|                     isPainting = true; |                     isPainting = true; | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if (isPainting) { |                 if (isPainting) { | ||||||
|                     pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin); |                     pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||||
|                     pdPageContentStream.stroke(); |                     pdPageContentStream.stroke(); | ||||||
|                     isPainting = false; |                     isPainting = false; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (isPainting) { |         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(); |             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. |         // 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++) { |         for (int x = 0; x < labyrinth.getWidth(); x++) { | ||||||
|             boolean isPainting = false; |             boolean isPainting = false; | ||||||
|             for (int y = 0; y < labyrinth.getHeight(); y++) { |             for (int y = 0; y < labyrinth.getHeight(); y++) { | ||||||
|                 final Tile currentTile = labyrinth.getTileAt(x, y); |                 final Tile currentTile = labyrinth.getTileAt(x, y); | ||||||
|                 if (currentTile.hasWallAt(Direction.LEFT)) { |                 if (currentTile.hasWallAt(Direction.LEFT)) { | ||||||
|                     if (!isPainting) { |                     if (!isPainting) { | ||||||
|                         pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin); |                         pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||||
|                         isPainting = true; |                         isPainting = true; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     if (isPainting) { |                     if (isPainting) { | ||||||
|                         pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin); |                         pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||||
|                         pdPageContentStream.stroke(); |                         pdPageContentStream.stroke(); | ||||||
|                         isPainting = false; |                         isPainting = false; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if (isPainting) { |             if (isPainting) { | ||||||
|                 pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - labyrinth.getHeight() * scale + margin); |                 pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - labyrinth.getHeight() * SCALE + MARGIN); | ||||||
|                 pdPageContentStream.stroke(); |                 pdPageContentStream.stroke(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -131,20 +153,56 @@ public class PDFRenderer implements Renderer<byte[]> { | ||||||
|             final Tile currentTile = labyrinth.getTileAt(x - 1, y); |             final Tile currentTile = labyrinth.getTileAt(x - 1, y); | ||||||
|             if (currentTile.hasWallAt(Direction.RIGHT)) { |             if (currentTile.hasWallAt(Direction.RIGHT)) { | ||||||
|                 if (!isPainting) { |                 if (!isPainting) { | ||||||
|                     pdPageContentStream.moveTo(x * scale + margin, labyrinthHeight - y * scale + margin); |                     pdPageContentStream.moveTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||||
|                     isPainting = true; |                     isPainting = true; | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if (isPainting) { |                 if (isPainting) { | ||||||
|                     pdPageContentStream.lineTo(x * scale + margin, labyrinthHeight - y * scale + margin); |                     pdPageContentStream.lineTo(x * SCALE + MARGIN, labyrinthHeight - y * SCALE + MARGIN); | ||||||
|                     pdPageContentStream.stroke(); |                     pdPageContentStream.stroke(); | ||||||
|                     isPainting = false; |                     isPainting = false; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (isPainting) { |         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(); |             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