function ok = CheckPos(game, tilenum, row, col, orientation)
% Checks if a tile was placed according to the rules. This means that all
% sides must match their neighboring sides, and that there must be at least
% 1 neighboring tile present, i.e. no islands.
G = get(game.imgH, 'UserData');
specs = get(game.figH, 'UserData');
ok = false;
%% MOST ELEMENTARY CHECK: IS IT AN EMPTY SPACE?
if any([row, col] > size(G,1)) || G(row, col, 1) ~= 0
return
end
%% WIDEN THE FIELD A LITTLE
% Place field in a new (temporary) field to avoid boundary issues
% when checking the adjecent tiles
n = size(G,1);
Gtemp = zeros(n + 2, n + 2, 4);
Gtemp(2:end-1, 2:end-1, :) = G;
%% FIND NEIGHBORS
i = row + 1;
j = col + 1;
% Adjecent tiles (numbers)
adjecNums = [Gtemp(i-1, j, 1);... N
Gtemp(i, j+1, 1);... E
Gtemp(i+1, j, 1);... S
Gtemp(i, j-1, 1)]; %W
% Adjecent tiles (orientations)
adjecOris = [Gtemp(i-1, j, 2);... N
Gtemp(i, j+1, 2);... E
Gtemp(i+1, j, 2);... S
Gtemp(i, j-1, 2)]; %W
%% CHECK FOR NEIGHBORS
if ~any(adjecNums)
return % No adjecent tiles
end
%% SIDES AFTER ROTATION
HomeSides = rotate(specs(tilenum, 2:3:11), orientation);
%% CHECK IF SIDES MATCH THOSE OF NEIGHBORS
opposite = @(x) mod(x+2, 4) + 4 * (mod(x+2, 4) == 0);
for side = 1:4 % for each side/adjecent tile
if adjecNums(side) == 0
continue % empty
end
% Sides of adjecent tile after rotation
OtherSides = rotate(specs(adjecNums(side), 2:3:11), adjecOris(side));
% Check sides
HomeSides(HomeSides == 4) = 2;
OtherSides(OtherSides == 4) = 2;
if HomeSides(side) ~= OtherSides(opposite(side))
return;
end
end
ok = true;
if ~game.playRivers
return
end
if ~any(specs(tilenum, 1:12) == 5)
return % not a river-tile
end
%% RIVER PHASE
% The official rules tell us that a river is NOT allowed to make U-turns.
% This is in order to shrink the chance of creating an unfinished river.
% However, it is still posible to create an unfinished river using only
% this rule. This is why I add 2 additional rules that will ensure a river
% to be finished, ending in the lake:
% 1. Rivers have to be placed 'river-to-river'.
% 2. A river may NOT flow East-West (opposite to start-direction)
%
% The user may uncheck the forcing of a completed river. In this case, a
% river-tile is just any other tile, no rules whatsoever!
if ~game.forcecompletedriver
return
end
ok = false;
% STEP 1: Check if the tile was placed 'river-to-river'
riverside = find(HomeSides == 5);
other = adjecNums(riverside);
if all(other == 0)
return
end
% STEP 2: Check if the river flows East-West
if riverside(other == 0) == 4
return % river exits to the West
end
% STEP 3: Check for U-turns (north-south and vice versa)
% Entrance-side of 'other' may not equal Exitside of current tile.
riverside = riverside(other ~=0);
other = other(other ~= 0);
otherSides = rotate(specs(other, 2:3:11), adjecOris(riverside));
entranceOther = find(otherSides == 5);
entranceOther = entranceOther(entranceOther ~= opposite(riverside));
if isempty(entranceOther)
ok = true;
return
end
exitCurrent = find(HomeSides == 5);
exitCurrent = exitCurrent(exitCurrent ~= riverside);
if entranceOther == exitCurrent
return
end
% OK!
ok = true;