package rabbitescape.engine;
import static rabbitescape.engine.CellularDirection.DOWN;
import static rabbitescape.engine.CellularDirection.LEFT;
import static rabbitescape.engine.CellularDirection.RIGHT;
import static rabbitescape.engine.CellularDirection.UP;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import rabbitescape.engine.Block.Shape;
import rabbitescape.engine.util.LookupTable2D;
import rabbitescape.engine.util.Position;
import rabbitescape.engine.util.WaterUtil;
public class WaterRegionFactory
{
/**
* Generate a 2D lookup table of water regions based on a 2D table of
* blocks.
*
* @param blockTable
* The table of blocks.
* @param waterAmounts
* Any water region contents that are currently known.
*/
public static LookupTable2D<WaterRegion> generateWaterTable(
LookupTable2D<Block> blockTable, Map<Position, Integer> waterAmounts )
{
LookupTable2D<WaterRegion> waterTable = new LookupTable2D<>( blockTable.size );
for ( int x = -1; x <= blockTable.size.width; x++ )
{
for ( int y = -1; y <= blockTable.size.height; y++ )
{
createWaterRegionsAtPoint( blockTable, waterTable, x, y );
Integer waterAmount = waterAmounts.get( new Position( x, y ) );
if ( waterAmount != null )
{
waterTable.getItemAt( x, y ).setContents( waterAmount );
}
}
}
return waterTable;
}
/** Create water regions at a given point based on a 2D table of blocks. */
public static void createWaterRegionsAtPoint(
LookupTable2D<Block> blockTable,
LookupTable2D<WaterRegion> waterTable,
int x,
int y )
{
List<Block> blocks = blockTable.getItemsAt( x, y );
Shape[] shapes = new Shape[blocks.size()];
for ( int i = 0; i < blocks.size(); i++ )
{
shapes[i] = blocks.get( i ).shape;
}
boolean outsideWorld = ( x == -1 || x == blockTable.size.width
|| y == -1 || y == blockTable.size.height );
List<WaterRegion> waterRegions = makeWaterRegion( x, y, shapes, outsideWorld );
waterTable.addAll( waterRegions );
}
/** Create a set of water regions from the given shaped blocks. */
public static List<WaterRegion> makeWaterRegion( int x, int y, Shape[] shapes, boolean outsideWorld )
{
Set<CellularDirection> connections = new HashSet<>(
Arrays.asList( UP, LEFT, RIGHT, DOWN ) );
for ( Shape shape : shapes )
{
switch ( shape )
{
case FLAT:
// This shape fills the whole space.
return Collections.<WaterRegion>emptyList();
case UP_RIGHT:
connections.remove( DOWN );
connections.remove( RIGHT );
break;
case UP_LEFT:
connections.remove( DOWN );
connections.remove( LEFT );
break;
// TODO Consider whether bridges should cause there to be two water regions.
case BRIDGE_UP_LEFT:
case BRIDGE_UP_RIGHT:
break;
default:
throw new IllegalArgumentException( "Unrecognised shape: " + shape );
}
}
int capacity = findCapacity( connections );
return Arrays.asList(
new WaterRegion( x, y,
connections,
capacity, outsideWorld ) );
}
private static int findCapacity( Set<CellularDirection> connections )
{
if ( connections.size() == 4 )
{
return WaterUtil.MAX_CAPACITY;
}
else if ( connections.size() == 3 )
{
System.out.println( "Unexpected combination of shapes has produced the connections: " + connections );
// Grudgingly we can calculate the amount.
return WaterUtil.HALF_CAPACITY + WaterUtil.QUARTER_CAPACITY;
}
else if ( connections.size() == 2 )
{
return WaterUtil.HALF_CAPACITY;
}
else if ( connections.size() == 1 )
{
return WaterUtil.QUARTER_CAPACITY;
}
return 0;
}
}