public boolean isTilePlacementAllowed(Tile tile, Position p) {
if (tile.getRiver() == null) return true;
for (Entry<Location, Tile> e : getBoard().getAdjacentTilesMap(p).entrySet()) {
//check river connection
Location tileRelativePosition = e.getKey();
Tile placedTile = e.getValue();
if (placedTile.getRiver() == null) return false; //e.g. count of carcassone preplaced tiles
boolean r1 = tileRelativePosition.rotateCCW(tile.getRotation()).isPartOf(tile.getRiver());
boolean r2 = tileRelativePosition.rotateCCW(placedTile.getRotation()).rev().isPartOf(placedTile.getRiver());
if (!(r1 & r2)) return false;
//check U-turn
Location continueRiver = tile.getRiver().rotateCW(tile.getRotation()).substract(tileRelativePosition);
if (continueRiver == Location.INNER_FARM) return true; //lake
for (Location continueSide: Location.sides()) { //split beacuse of river fork
if (continueRiver.intersect(continueSide) == null) continue;
Position pCheck = p.add(continueSide).add(continueSide.rotateCW(Rotation.R90));
if (getBoard().get(pCheck) != null) return false;
pCheck = p.add(continueSide).add(continueSide.rotateCCW(Rotation.R90));
if (getBoard().get(pCheck) != null) return false;
pCheck = p.add(continueSide).add(continueSide);