/* This file is part of Eternity II Editor.
*
* Eternity II Editor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Eternity II Editor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Eternity II Editor. If not, see <http://www.gnu.org/licenses/>.
*
* Eternity II Editor project is hosted on SourceForge:
* http://sourceforge.net/projects/eternityii/
* and maintained by Yannick Kirschhoffer <alcibiade@alcibiade.org>
*/
package org.alcibiade.eternity.editor.model;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.regex.Matcher;
public class GridModel extends AbstractQuadGrid implements Cloneable {
private static final long serialVersionUID = 1L;
private boolean readOnly;
private Set<GridObserver> gridObservers = new HashSet<GridObserver>();
private Pattern defaultpat;
public GridModel() {
this(2);
}
public GridModel(int size) {
super(size, size);
defaultpat = Pattern.getDefaultPattern();
readOnly = false;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
for (QuadModel quad : gridQuads) {
quad.setReadOnly(readOnly);
}
}
@Override
public GridModel clone() {
GridModel newgrid = new GridModel(getSize());
for (int i = 0; i < gridQuads.size(); i++) {
newgrid.gridQuads.set(i, gridQuads.get(i).clone());
}
return newgrid;
}
public int getSize() {
return super.getWidth();
}
public void setSize(int size) {
assert !readOnly;
super.setSize(size, size);
notifyGridSizeUpdated();
}
public void copyTo(GridModel destGrid) {
if (destGrid.getSize() != getSize()) {
destGrid.setSize(getSize());
}
for (int i = 0; i < gridQuads.size(); i++) {
getQuad(i).copyTo(destGrid.getQuad(i), false);
}
destGrid.notifyGridUpdated();
}
public void reset() {
assert !readOnly;
for (QuadModel quad : gridQuads) {
quad.clear();
}
}
public void shuffle() {
assert !readOnly;
Random rand = new Random();
for (int i = 0; i < getSize() * getSize(); i++) {
int swap_pos = rand.nextInt(getSize() * getSize());
int rotations = rand.nextInt(4);
QuadModel quad = gridQuads.get(i);
QuadModel target = gridQuads.get(swap_pos);
if (!quad.isLocked() && !target.isLocked()) {
quad.rotateClockwise(rotations);
quad.swap(target);
}
}
}
public void addGridObserver(GridObserver observer) {
gridObservers.add(observer);
}
public void removeGridObserver(GridObserver observer) {
gridObservers.remove(observer);
}
public boolean isComplete() {
return countPairs() == countConnections();
}
public int countConnections() {
return 2 * getSize() * (getSize() - 1);
}
public int countPairs() {
int pairs = 0;
for (int y = 0; y < getSize(); y++) {
for (int x = 0; x < getSize(); x++) {
QuadModel quad = getQuad(x, y);
if (x < getSize() - 1) {
QuadModel eastquad = getQuad(x + 1, y);
Pattern eastpat = quad.getPattern(QuadModel.DIR_EAST);
if (eastpat != defaultpat && eastpat == eastquad.getPattern(QuadModel.DIR_WEST)) {
pairs++;
}
}
if (y < getSize() - 1) {
QuadModel southquad = getQuad(x, y + 1);
Pattern southpat = quad.getPattern(QuadModel.DIR_SOUTH);
if (southpat != defaultpat
&& southpat == southquad.getPattern(QuadModel.DIR_NORTH)) {
pairs++;
}
}
}
}
return pairs;
}
public int countPairs(int index) {
return countPairs(index % getSize(), index / getSize());
}
public int countPairs(int x, int y) {
return countPairs(x, y, 1);
}
public int countPairs(int x, int y, int borderweight) {
if (x < 0 || x >= getSize() || y < 0 || y >= getSize()) {
return 0;
}
int pairs = 0;
QuadModel quad = getQuad(x, y);
if (x == 0) {
if (quad.getPattern(QuadModel.DIR_WEST) == defaultpat) {
pairs += borderweight;
}
} else {
QuadModel westquad = getQuad(x - 1, y);
Pattern westpat = quad.getPattern(QuadModel.DIR_WEST);
if (westpat != defaultpat && westpat == westquad.getPattern(QuadModel.DIR_EAST)) {
pairs++;
}
}
if (x < getSize() - 1) {
QuadModel eastquad = getQuad(x + 1, y);
Pattern eastpat = quad.getPattern(QuadModel.DIR_EAST);
if (eastpat != defaultpat && eastpat == eastquad.getPattern(QuadModel.DIR_WEST)) {
pairs++;
}
} else {
if (quad.getPattern(QuadModel.DIR_EAST) == defaultpat) {
pairs += borderweight;
}
}
if (y == 0) {
if (quad.getPattern(QuadModel.DIR_NORTH) == defaultpat) {
pairs += borderweight;
}
} else {
QuadModel northquad = getQuad(x, y - 1);
Pattern northpat = quad.getPattern(QuadModel.DIR_NORTH);
if (northpat != defaultpat && northpat == northquad.getPattern(QuadModel.DIR_SOUTH)) {
pairs++;
}
}
if (y < getSize() - 1) {
QuadModel southquad = getQuad(x, y + 1);
Pattern southpat = quad.getPattern(QuadModel.DIR_SOUTH);
if (southpat != defaultpat && southpat == southquad.getPattern(QuadModel.DIR_NORTH)) {
pairs++;
}
} else {
if (quad.getPattern(QuadModel.DIR_SOUTH) == defaultpat) {
pairs += borderweight;
}
}
return pairs;
}
public int countOccurences(Pattern pattern) {
int occurences = 0;
for (QuadModel quad : gridQuads) {
if (quad.getPattern(QuadModel.DIR_NORTH) == pattern) {
occurences++;
}
if (quad.getPattern(QuadModel.DIR_SOUTH) == pattern) {
occurences++;
}
if (quad.getPattern(QuadModel.DIR_EAST) == pattern) {
occurences++;
}
if (quad.getPattern(QuadModel.DIR_WEST) == pattern) {
occurences++;
}
}
return occurences;
}
public int countOpenOccurences(Pattern pattern) {
int result = 0;
for (int y = 0; y < getSize(); y++) {
for (int x = 0; x < getSize(); x++) {
QuadModel quad = getQuad(x, y);
QuadModel quad_n = getQuad(x, y - 1);
QuadModel quad_e = getQuad(x + 1, y);
QuadModel quad_s = getQuad(x, y + 1);
QuadModel quad_w = getQuad(x - 1, y);
if (quad.getPattern(QuadModel.DIR_NORTH) == pattern && quad_n != null
&& quad_n.isClear()) {
result++;
}
if (quad.getPattern(QuadModel.DIR_EAST) == pattern && quad_e != null
&& quad_e.isClear()) {
result++;
}
if (quad.getPattern(QuadModel.DIR_SOUTH) == pattern && quad_s != null
&& quad_s.isClear()) {
result++;
}
if (quad.getPattern(QuadModel.DIR_WEST) == pattern && quad_w != null
&& quad_w.isClear()) {
result++;
}
}
}
return result;
}
public String getStatusMessage() {
String message = null;
List<Pattern> allpatterns = Pattern.getAllPatterns();
for (Pattern pattern : allpatterns) {
int occurences = countOccurences(pattern);
if (pattern == Pattern.getDefaultPattern()) {
int desired = 4 * getSize();
if (occurences < desired) {
message = "Too few border tiles";
} else if (occurences > desired) {
message = "Too many border tiles";
}
} else {
if ((occurences % 2) == 1) {
message = "Odd amount of pat. " + pattern.getCode();
}
}
}
if (message == null) {
message = "Ok";
}
return message;
}
public void fromQuadString(String text) throws QuadsFormatException {
assert !readOnly;
text = stripComments(text);
StringTokenizer stok = new StringTokenizer(text);
int patternCount = countTextPatterns(text);
double gridsize = Math.sqrt(patternCount / 4);
if (gridsize != Math.round(gridsize) || gridsize < 2) {
throw new QuadsFormatException("Inconsistent grid size. " + patternCount
+ " values found instead of n * n * 4");
}
int i_gridsize = (int) Math.round(gridsize);
int ix_quad = 0;
int ix_dir = 0;
boolean lock = false;
List<QuadModel> quadbuffer = new ArrayList<QuadModel>();
while (stok.hasMoreTokens() && ix_quad < i_gridsize * i_gridsize) {
int pattern_code;
String token = stok.nextToken();
if (token.contains("[")) {
lock = true;
token = token.replaceAll("\\[", "");
}
if (token.contains("]")) {
lock = false;
token = token.replaceAll("\\]", "");
}
if (token.length() > 0) {
try {
pattern_code = Integer.parseInt(token);
} catch (NumberFormatException ex) {
throw new QuadsFormatException("Incorrect number format '" + token + "'");
}
Pattern pattern = Pattern.getPatternByCode(pattern_code);
if (pattern == null) {
throw new QuadsFormatException("Unknown pattern code " + pattern_code);
}
while (ix_quad >= quadbuffer.size()) {
QuadModel quad = new QuadModel();
quad.setLocked(lock);
quadbuffer.add(quad);
}
if (pattern != null) {
quadbuffer.get(ix_quad).setPattern(ix_dir, pattern);
ix_dir++;
if (ix_dir == 4) {
ix_dir = 0;
ix_quad++;
}
}
}
}
setSize(i_gridsize);
for (int qi = 0; qi < quadbuffer.size(); qi++) {
quadbuffer.get(qi).copyTo(gridQuads.get(qi));
}
}
private String stripComments(String text) {
text = text.replace('\r', '\n');
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("#.*[\n]",
java.util.regex.Pattern.MULTILINE);
Matcher matcher = pattern.matcher(text);
text = matcher.replaceAll("");
return text;
}
private static int countTextPatterns(String text) {
StringTokenizer stok = new StringTokenizer(text, "\n \t[]");
return stok.countTokens();
}
private void notifyGridSizeUpdated() {
for (GridObserver observer : gridObservers) {
observer.gridSizeUpdated(getSize());
}
}
private void notifyGridUpdated() {
for (GridObserver observer : gridObservers) {
observer.gridUpdated();
}
}
public int optimizeQuadRotation(int index) {
assert !readOnly;
int bestOrientation = 0;
int best_pairs = 0;
int x = index % getSize();
int y = index / getSize();
QuadModel quad = getQuad(index);
for (int i = 0; i < 4; i++) {
int pairs = countPairs(x, y, 4);
if (pairs > best_pairs) {
best_pairs = pairs;
bestOrientation = i;
}
quad.rotateClockwise();
}
quad.rotateClockwise(bestOrientation);
return bestOrientation;
}
public void swap(int indexA, int indexB) {
assert !readOnly;
QuadModel quadA = getQuad(indexA);
QuadModel quadB = getQuad(indexB);
QuadModel buffer = new QuadModel();
quadA.copyTo(buffer);
quadB.copyTo(quadA);
buffer.copyTo(quadB);
}
public QuadModel getMissingQuad(int index) {
int x = index % getSize();
int y = index / getSize();
return getMissingQuad(x, y);
}
public QuadModel getMissingQuad(int x, int y) {
QuadModel quad = new QuadModel();
for (int d = 0; d < 4; d++) {
QuadModel neighbor = getNeighbor(x, y, d);
Pattern missingPattern;
if (neighbor == null) {
missingPattern = defaultpat;
} else {
int oppD = (d + 2) % 4;
missingPattern = neighbor.getPattern(oppD);
if (missingPattern == defaultpat) {
missingPattern = null;
}
}
quad.setPattern(d, missingPattern);
}
return quad;
}
public List<Integer> getMatchingQuads(QuadModel missing, int degrees) {
List<Integer> matches = new ArrayList<Integer>();
int sides = missing.countPattern(defaultpat);
for (int i = 0; i < gridQuads.size(); i++) {
QuadModel q = gridQuads.get(i);
if (q.equalsIgnoreRotation(missing, degrees) && q.countPattern(defaultpat) == sides) {
matches.add(i);
}
}
return matches;
}
public PatternStats getPatternStats() {
SortedSet<Pattern> patterns = new TreeSet<Pattern>();
SortedSet<Pattern> innerPatterns = new TreeSet<Pattern>();
SortedSet<Pattern> outerPatterns = new TreeSet<Pattern>();
int duplicates = 0;
for (int y = 0; y < getSize(); y++) {
for (int x = 0; x < getSize(); x++) {
QuadModel quad = getQuad(x, y);
for (int dy = y; dy < getSize(); dy++) {
for (int dx = 0; dx < getSize(); dx++) {
if (dy > y || dx > x) {
QuadModel q2 = getQuad(dx, dy);
if (quad.equalsIgnoreRotation(q2)) {
duplicates += 1;
}
}
}
}
for (int d = 0; d < 4; d++) {
Pattern pattern = quad.getPattern(d);
if (pattern != defaultpat) {
patterns.add(pattern);
if ((x == 0 || x == getSize() - 1)
&& (d == QuadModel.DIR_NORTH || d == QuadModel.DIR_SOUTH)) {
outerPatterns.add(pattern);
} else if ((y == 0 || y == getSize() - 1)
&& (d == QuadModel.DIR_WEST || d == QuadModel.DIR_EAST)) {
outerPatterns.add(pattern);
} else {
innerPatterns.add(pattern);
}
}
}
}
}
return new PatternStats(patterns, outerPatterns, innerPatterns, duplicates);
}
public boolean isHSymetric() {
GridModel g2 = clone();
g2.flipHorizontal();
return equals(g2);
}
public boolean isVSymetric() {
GridModel g2 = clone();
g2.flipVertical();
return equals(g2);
}
public boolean isRSymetric() {
GridModel g2 = clone();
g2.rotateClockwise();
return equals(g2);
}
public int countExternalBorders(int index) {
int borders = countExternalBorders(index % getSize(), index / getSize());
return borders;
}
public int countExternalBorders(int x, int y) {
int borders = 0;
if (x == 0 || x == getSize() - 1) {
borders++;
}
if (y == 0 || y == getSize() - 1) {
borders++;
}
return borders;
}
public void rotateClockwise(int steps) {
assert !readOnly;
for (int i = 0; i < steps; i++) {
rotateClockwise();
}
}
public void rotateCounterclockwise(int steps) {
assert !readOnly;
for (int i = 0; i < steps; i++) {
rotateCounterclockwise();
}
}
public void rotateCounterclockwise() {
assert !readOnly;
rotateClockwise(3);
}
public void rotateClockwise() {
assert !readOnly;
List<QuadModel> originalQuads = new ArrayList<QuadModel>();
for (QuadModel quad : gridQuads) {
originalQuads.add(quad.clone());
}
for (int y = 0; y < getSize(); y++) {
for (int x = 0; x < getSize(); x++) {
QuadModel source = originalQuads.get(x + getSize() * y);
QuadModel destination = gridQuads.get((getSize() - 1 - y) + (getSize() * x));
source.copyTo(destination);
destination.rotateClockwise();
}
}
}
public void rotateCenterClockwise(int steps) {
assert !readOnly;
for (int i = 0; i < steps; i++) {
rotateCenterClockwise();
}
}
public void rotateCenterClockwise() {
assert !readOnly;
List<QuadModel> originalQuads = new ArrayList<QuadModel>();
for (QuadModel quad : gridQuads) {
originalQuads.add(quad.clone());
}
for (int y = getSize() / 2 - 1; y <= (getSize() + 1) / 2; y++) {
for (int x = getSize() / 2 - 1; x <= (getSize() + 1) / 2; x++) {
QuadModel source = originalQuads.get(x + getSize() * y);
QuadModel destination = gridQuads.get((getSize() - 1 - y) + (getSize() * x));
source.copyTo(destination);
destination.rotateClockwise();
}
}
}
public void rotateCenterCounterclockwise(int steps) {
assert !readOnly;
for (int i = 0; i < steps; i++) {
rotateCenterCounterclockwise();
}
}
public void rotateCenterCounterclockwise() {
assert !readOnly;
rotateCenterClockwise(3);
}
public void flipVertical() {
assert !readOnly;
rotateClockwise();
flipHorizontal();
rotateCounterclockwise();
}
public void flipHorizontal() {
assert !readOnly;
List<QuadModel> originalQuads = new ArrayList<QuadModel>();
for (QuadModel quad : gridQuads) {
originalQuads.add(quad.clone());
}
int size = getSize();
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
QuadModel source = originalQuads.get(x + size * y);
QuadModel destination = gridQuads.get((size - 1 - x) + (size * y));
source.copyTo(destination);
destination.flipHorizontal();
}
}
}
/*
* GENETIC ALGORITHMS
*/
/*
* Counts the number of non-empty quads on this grid
*/
public int countFilledQuads() {
int count = 0;
for(int i = 0; i < this.getPositions(); i++)
if(!this.getQuad(i).isClear())
count++;
return count;
}
/*
* Counts the number of quads equivalent to the given quad on this grid
*/
public int countQuadOccurences(QuadModel q) {
int count = 0;
for(int i = 0; i < this.getPositions(); i++)
if(q.equalsIgnoreRotation(this.getQuad(i)))
count++;
return count;
}
/*
* Returns a Set of the positions that are not empty on this grid
*/
public TreeSet<Integer> getFilledPositions() {
TreeSet<Integer> positions = new TreeSet<Integer>();
for(int i = 0; i < this.getPositions(); i++)
if(!this.getQuad(i).isClear())
positions.add(i);
return positions;
}
/*
* Given 2 incomplete GridModels, checks if there are no duplicate pieces in
* both boards.
* Assumes piece positions from "a" and "b" do not overlap.
*/
public boolean allPiecesValid(GridModel a, GridModel b) {
boolean allValid = true;
GridModel incomplete = GridModel.joinGrids(a, b);
// if the occurences of the pieces in both "original" and "incomplete"
// differ, the features are incompatible
for(int i = 0; allValid && i < incomplete.getPositions(); i++) {
QuadModel q = incomplete.getQuad(i);
if(q.isClear()) continue;
if(this.countQuadOccurences(q) < incomplete.countQuadOccurences(q))
allValid = false;
}
return allValid;
}
/*
* Joins two incomplete boards. Assumes "a" and "b" have no overlapping pieces
*/
public static GridModel joinGrids(GridModel a, GridModel b) {
GridModel join = a.clone();
for(int i = 0; i < b.getPositions(); i++) {
if(b.getQuad(i).isClear()) continue;
join.setQuad(i, b.getQuad(i));
}
return join;
}
/* given an incomplete board, return the pieces of the complete
* board that can be used to complete the incomplete board
*/
public GridModel remainingPieces(GridModel incomplete) {
GridModel remaining = this.clone();
remaining.setReadOnly(false);
for(int i = 0; i < incomplete.getPositions(); i++) {
QuadModel qi = incomplete.getQuad(i);
if(!qi.isClear()) {
for(int j = 0; j < remaining.getPositions(); j++) {
QuadModel qr = remaining.getQuad(j);
if(qr.geneticEquals(qi)) {
qr.clear();
break;
}
}
}
}
return remaining;
}
public int getTestScore(int index) {
return getTestScore(getQuad(index), index);
}
//
public int getTestScore(QuadModel testQuad, int index) {
int score = 0;
for (int dir = 0; dir < 4; dir++) {
QuadModel neighbor = getNeighbor(index, dir);
if (neighbor != null && testQuad.getPattern(dir) == neighbor.getOppositePattern(dir) && testQuad.getPattern(dir) != Pattern.getDefaultPattern())
score++;
if (neighbor == null && testQuad.getPattern(dir) == Pattern.getDefaultPattern())
score++;
}
return score;
}
//
public boolean isIndexOnBorder(int index) {
if(index < this.getSize() || (index >= (this.getSize()*this.getSize() - this.getSize())))
return true;
if(index % this.getSize() == 0 || (index+1) % this.getSize() == 0 )
return true;
return false;
}
public void completeWith(GridModel remaining) {
QuadModel current, candidate, bestQuad;
int bestScore;
int score;
int candidatePos = 0; // for clearing
for(int i = 0; i < this.getPositions(); i++) {
current = this.getQuad(i);
if(!current.isClear()) continue;
bestScore = -1;
bestQuad = null;
// get best candidate piece from remaining
for(int c = 0; c < remaining.getPositions(); c++) {
candidate = remaining.getQuad(c).clone();
if(candidate.isClear()) continue;
for (int d = 0; d < 4; d++) {
candidate.rotateClockwise();
score = getTestScore(candidate, i);
if (score > bestScore) {
bestScore = score;
bestQuad = candidate;
candidatePos = c;
}
}
}
this.setQuad(i, bestQuad);
remaining.getQuad(candidatePos).clear();
}
}
/*
* Tries to return the best grid containing compatible features from A joined with B
* If there is no compatible features in B, returns a grid with the best feature from A
*/
public GridModel getCompatibleFeatures(ArrayList<GridModel> featuresA, ArrayList<GridModel> featuresB) {
GridModel fa = null;
// select best feature from a
for(GridModel g : featuresA) {
if(fa == null) fa = g.clone();
if(g.countFilledQuads() > fa.countFilledQuads()) g.copyTo(fa);
}
// try to get a compatible feature from b
for(GridModel fb : featuresB) {
// are the positions compatible? (i.e., not overlapping?)
TreeSet<Integer> overlapping = fa.getFilledPositions();
overlapping.retainAll(fb.getFilledPositions());
/*System.out.println(fa.toQuadString());
System.out.println(fb.toQuadString());
System.out.println(overlapping.size());
System.out.println("\n-------------\n");*/
if(overlapping.size() == 0 && this.allPiecesValid(fa, fb)) {
return GridModel.joinGrids(fa,fb);
}
}
return fa;
}
// iterative approach
public ArrayList<GridModel> getFeatures() {
Set<Integer> visited = new TreeSet<Integer>();
ArrayList<GridModel> features = new ArrayList<GridModel>();
for(int i = 0; i < this.getPositions(); i++) {
if(!visited.contains(i)) {
GridModel feature = new GridModel(this.getSize());
getFeatures(i, feature, visited);
features.add(feature);
}
}
return features;
}
private void getFeatures(int index, GridModel feature, Set<Integer> visited) {
QuadModel current = this.getQuad(index);
feature.setQuad(index, current);
for(int dir = 0; dir < 4; dir++) {
QuadModel neighbor = this.getNeighbor(index, dir);
int neighborIndex = this.computeNeighborIndex(index, dir);
if((neighbor != null)) {
if(feature.getQuad(neighborIndex).isClear()) {
if(!visited.contains(neighborIndex)) {
if(current.getPattern(dir) == neighbor.getOppositePattern(dir)) {
getFeatures(neighborIndex, feature, visited);
}
}
}
}
}
visited.add(index);
}
/* for the regular fitness function */
public int borderlineConnections() {
return 2*getWidth() + 2*getHeight();
}
public int borderlinePairs() {
int pairs = 0;
//Count horizontal pairs
for (int i = 0; i < getSize(); i++) {
if (getQuad(i, 0).getPattern(QuadModel.DIR_NORTH) == Pattern.getDefaultPattern())
pairs++;
if (getQuad(i, getHeight()-1).getPattern(QuadModel.DIR_SOUTH) == Pattern.getDefaultPattern())
pairs++;
if (getQuad(0, i).getPattern(QuadModel.DIR_WEST) == Pattern.getDefaultPattern())
pairs++;
if (getQuad(getWidth()-1, i).getPattern(QuadModel.DIR_EAST) == Pattern.getDefaultPattern())
pairs++;
}
return pairs;
}
/* for the weighted fitness function */
public int borderConnections() {
return 2*getWidth() + 2*getHeight() - 2*4;
}
public int borderPairs() {
int pairs = 0;
//Count horizontal pairs
for (int i = 1; i < getSize()-1; i++) {
if (getQuad(i, 0).getPattern(QuadModel.DIR_NORTH) == Pattern.getDefaultPattern())
pairs++;
if (getQuad(i, getHeight()-1).getPattern(QuadModel.DIR_SOUTH) == Pattern.getDefaultPattern())
pairs++;
if (getQuad(0, i).getPattern(QuadModel.DIR_WEST) == Pattern.getDefaultPattern())
pairs++;
if (getQuad(getWidth()-1, i).getPattern(QuadModel.DIR_EAST) == Pattern.getDefaultPattern())
pairs++;
}
return pairs;
}
public int cornerConnections() {
return 8;
}
public int cornerPairs() {
int pairs = 0;
int s = getSize()-1;
QuadModel topLeftQuad = getQuad(0,0);
QuadModel topRightQuad = getQuad(s,0);
QuadModel bottomLeftQuad = getQuad(0,s);
QuadModel bottomRightQuad = getQuad(s,s);
if ((topLeftQuad.getPattern(QuadModel.DIR_NORTH) == Pattern.getDefaultPattern())
&& (topLeftQuad.getPattern(QuadModel.DIR_WEST) == Pattern.getDefaultPattern()))
pairs += 2;
if ((topRightQuad.getPattern(QuadModel.DIR_NORTH) == Pattern.getDefaultPattern())
&& (topRightQuad.getPattern(QuadModel.DIR_EAST) == Pattern.getDefaultPattern()))
pairs += 2;
if ((bottomLeftQuad.getPattern(QuadModel.DIR_SOUTH) == Pattern.getDefaultPattern())
&& (bottomLeftQuad.getPattern(QuadModel.DIR_WEST) == Pattern.getDefaultPattern()))
pairs += 2;
if ((bottomRightQuad.getPattern(QuadModel.DIR_SOUTH) == Pattern.getDefaultPattern())
&& (bottomRightQuad.getPattern(QuadModel.DIR_EAST) == Pattern.getDefaultPattern()))
pairs += 2;
return pairs;
}
}