package enterprise;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Collections;
import java.util.Map.Entry;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;
public class Maze {
private final WallFactory<Double> wallFactory;
private final EntropyGenerator entropyGenerator;
public Maze( WallFactory<Double> wallFactory, EntropyGenerator entropyGenerator ) {
this.wallFactory = wallFactory;
this.entropyGenerator = entropyGenerator;
}
public void visit( MazeVisitor visitor ) throws MazeException {
while( true ) {
MazeWall wall = wallFactory.createMazeWall( entropyGenerator.getNewEntropyValue() );
wall.visit( visitor );
}
}
public interface MazeWall {
/**
* @param visitor
* @throws IOException
*/
void visit( MazeVisitor visitor ) throws MazeException;
}
public static class LeftDiagonalWall implements MazeWall {
@Override
public void visit( MazeVisitor visitor ) throws MazeException {
visitor.visit( this );
}
}
public static class RightDiagonalWall implements MazeWall {
@Override
public void visit( MazeVisitor visitor ) throws MazeException {
visitor.visit( this );
}
}
public interface MazeVisitor {
void visit( LeftDiagonalWall leftDiagonalWall ) throws MazeException;
void visit( RightDiagonalWall rightDiagonalWall ) throws MazeException;
}
public interface WallFactory<T> {
/**
* @param value
* @return the MazeWall
* @throws MazeException
*/
MazeWall createMazeWall( T value ) throws MazeException;
}
public static class StrategyWallFactory<T> implements WallFactory<T> {
private WallRepartitionStrategy<T> wallRepartitionStrategy;
public StrategyWallFactory( WallRepartitionStrategy<T> wallRepartitionStrategy ) {
this.wallRepartitionStrategy = wallRepartitionStrategy;
}
@Override
public MazeWall createMazeWall( T value ) throws MazeException {
Class<? extends MazeWall> wallClassForValue = wallRepartitionStrategy.getWallClassForValue( value );
try {
return wallClassForValue.newInstance();
} catch( InstantiationException | IllegalAccessException e ) {
throw new MazeException( "Cannot create MazeWall instance", e );
}
}
}
public interface WallRepartitionStrategy<T> {
/**
* @param value
* @return the wall class for value
* @throws MazeException
*/
Class<? extends MazeWall> getWallClassForValue( T value ) throws MazeException;
}
public static class ProbabilityThresholdWallRepartitionStrategy implements WallRepartitionStrategy<Double> {
private SortedMap<Double, Class<? extends MazeWall>> thresholds = new TreeMap<Double, Class<? extends MazeWall>>( Collections.reverseOrder() );
public void declareWallThreshold( Double probability, Class<? extends MazeWall> wallClass ) throws MazeException {
if( probability < 0 || probability > 1 ) {
throw new MazeException( "Invalid probability " + probability );
}
thresholds.put( probability, wallClass );
}
@Override
public Class<? extends MazeWall> getWallClassForValue( Double value ) throws MazeException {
for( Entry<Double, Class<? extends MazeWall>> entry : thresholds.entrySet() ) {
if( entry.getKey() < value ) {
return entry.getValue();
}
}
throw new MazeException( "No MazeWall class found for probabitity threshold " + value );
}
}
public static class MazePrintVisitor implements MazeVisitor {
private static final String LEFT_WALL_REPRESENTATION = "╱";
private static final String RIGHT_WALL_REPRESENTATION = "╲";
private final Writer writer;
private final int lineWidth;
private int count;
public MazePrintVisitor( Writer writer, int lineWidth ) {
this.writer = writer;
this.lineWidth = lineWidth;
}
@Override
public void visit( LeftDiagonalWall leftDiagonalWall ) throws MazeException {
print( LEFT_WALL_REPRESENTATION );
}
@Override
public void visit( RightDiagonalWall rightDiagonalWall ) throws MazeException {
print( RIGHT_WALL_REPRESENTATION );
}
private void print( String str ) throws MazeException {
try {
if( count >= lineWidth ) {
count = 0;
writer.write( System.lineSeparator() );
}
writer.write( str );
count += str.codePointCount( 0, str.length() );
} catch( IOException e ) {
throw new MazeException( "Error printing maze", e );
}
}
}
public interface EntropyGenerator {
double getNewEntropyValue();
}
public static class JavaRandomEntropyGenerator implements EntropyGenerator {
private Random random = new Random();
@Override
public double getNewEntropyValue() {
return random.nextDouble();
}
}
public static class MazeException extends Exception {
public MazeException( String message ) {
super( message );
}
public MazeException( String message, Throwable cause ) {
super( message, cause );
}
}
public static void main( String[] args ) throws Exception {
ProbabilityThresholdWallRepartitionStrategy repartitionStrategy = new ProbabilityThresholdWallRepartitionStrategy();
repartitionStrategy.declareWallThreshold( 0.0, LeftDiagonalWall.class );
repartitionStrategy.declareWallThreshold( 0.5, RightDiagonalWall.class );
WallFactory<Double> wallFactory = new StrategyWallFactory<Double>( repartitionStrategy );
EntropyGenerator entropyGenerator = new JavaRandomEntropyGenerator();
Maze maze = new Maze( wallFactory, entropyGenerator );
MazePrintVisitor printVisitor = new MazePrintVisitor( new OutputStreamWriter( System.out ), 40 );
maze.visit( printVisitor );
}
}