ca.draconic.stipple.wangtiles.RecursiveTile.java Source code

Java tutorial

Introduction

Here is the source code for ca.draconic.stipple.wangtiles.RecursiveTile.java

Source

/*
 * (c) 2014 - 2016 Kevin Smith
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  This program 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 Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @author Kevin Smith
 */
package ca.draconic.stipple.wangtiles;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import com.google.common.base.Preconditions;

public class RecursiveTile<T> extends Tile<T> {

    int k;

    RecursiveTile<T>[] subtiles;

    @SuppressWarnings("unchecked")
    protected RecursiveTile(TileSet<T> set, Tile<T> template, int k) {
        super(set, template);
        this.k = k;
        this.subtiles = new RecursiveTile[k * k];
    }

    protected RecursiveTileSet<T> getSet() {
        return (RecursiveTileSet<T>) this.set;
    }

    public RecursiveTile<T> getSubtile(int x, int y) {
        Preconditions.checkPositionIndex(x, k);
        Preconditions.checkPositionIndex(y, k);
        return subtiles[x + k * y];
    }

    protected void setSubtile(int x, int y, RecursiveTile<T> t) {
        Preconditions.checkPositionIndex(x, k);
        Preconditions.checkPositionIndex(y, k);
        Preconditions.checkArgument(t.set == this.set);
        subtiles[x + k * y] = t;
    }

    protected int errorsForSubtile(int x, int y) {
        return errorsForSubtile(x, y, getSubtile(x, y));
    }

    protected int errorsForSubtile(int x, int y, RecursiveTile<T> subtile) {
        final int subup, subdown, subleft, subright;
        Preconditions.checkPositionIndex(x, k);
        Preconditions.checkPositionIndex(y, k);

        if (x == 0) {
            subleft = getSet().colourSequences[this.left][y];
        } else {
            subleft = getSubtile(x - 1, y).right;
        }
        if (x == k - 1) {
            subright = getSet().colourSequences[this.right][y];
        } else {
            subright = getSubtile(x + 1, y).left;
        }
        if (y == 0) {
            subup = getSet().colourSequences[this.up][x];
        } else {
            subup = getSubtile(x, y - 1).down;
        }
        if (y == k - 1) {
            subdown = getSet().colourSequences[this.down][x];
        } else {
            subdown = getSubtile(x, y + 1).up;
        }

        int errors = 0;
        if (subup != subtile.up)
            errors++;
        if (subdown != subtile.down)
            errors++;
        if (subleft != subtile.left)
            errors++;
        if (subright != subtile.right)
            errors++;

        return errors;
    }

    protected int hasErrors() {
        int errorsum = 0;
        for (int x = 0; x < k; x++) {
            for (int y = 0; y < k; y++) {
                //                if(errorsForSubtile(x,y)>0) return true;
                errorsum += errorsForSubtile(x, y);
            }
        }
        return errorsum;
    }

    @SuppressWarnings("unchecked")
    protected RecursiveTile<T> getBetterTile(int x, int y, Random rand) {
        Preconditions.checkPositionIndex(x, k);
        Preconditions.checkPositionIndex(y, k);
        List<RecursiveTile<T>> better = new ArrayList<>();
        List<RecursiveTile<T>> equal = new ArrayList<>();
        int currentErrors = errorsForSubtile(x, y);
        RecursiveTile<T> currentTile = getSubtile(x, y);
        for (RecursiveTile<T> tile : (Set<RecursiveTile<T>>) set.getTiles()) {
            int newErrors = errorsForSubtile(x, y, tile);
            if (currentErrors > newErrors)
                better.add(tile);
            else if (currentErrors == newErrors && tile != currentTile)
                equal.add(tile);
        }
        if (!better.isEmpty())
            return better.get(rand.nextInt(better.size()));
        else if (!equal.isEmpty())
            return equal.get(rand.nextInt(equal.size()));
        else
            return currentTile;
    }

    protected boolean generateSubTiles(Random rand) {
        for (int i = 0; i < k * k; i++) {
            subtiles[i] = (RecursiveTile<T>) getSet().getTile(null, null, rand);
        }
        int maxTries = 1000;
        for (int tries = 0; tries < maxTries; tries++) {
            int totalErrors = hasErrors();
            //if(tries%(maxTries/10)==0) System.err.printf("errors: %d", totalErrors).println();
            if (totalErrors == 0)
                return true; // Tile is good, stop here

            int x = rand.nextInt(k);
            int y = rand.nextInt(k);

            int currentErrors = errorsForSubtile(x, y);
            assert currentErrors >= 0;

            if (currentErrors > 0) {
                RecursiveTile<T> newTile = (RecursiveTile<T>) getBetterTile(x, y, rand);
                setSubtile(x, y, newTile);
            }
        }

        return false; // Could not find a recursive tiling
    }
}