initial working import!

This commit is contained in:
foo 2016-12-17 21:45:03 +00:00
commit 865b8df406
4 changed files with 382 additions and 0 deletions

View File

@ -0,0 +1,19 @@
package uk.org.mafoo.wordsearch;
class Bounds {
int min_y;
int max_y;
int min_x;
int max_x;
protected Bounds(int min_y, int max_y, int min_x, int max_x) {
this.min_y = min_y;
this.max_y = max_y;
this.min_x = min_x;
this.max_x = max_x;
}
public String toString() {
return "[" + min_x + " < x < " + max_x + " & " + min_y + " < y < " + max_y +"]";
}
}

View File

@ -0,0 +1,7 @@
package uk.org.mafoo.wordsearch;
class CouldNotPlaceWordException extends Exception {
protected CouldNotPlaceWordException() {
}
}

View File

@ -0,0 +1,37 @@
package uk.org.mafoo.wordsearch;
import java.util.*;
// http://stackoverflow.com/questions/20327958/random-number-with-probabilities#20328491
public class DistributedRandomNumberGenerator {
private HashMap<Integer, Double> distribution;
private double distSum;
public DistributedRandomNumberGenerator() {
distribution = new HashMap<>();
}
public void addNumber(int value, double distribution) {
if (this.distribution.get(value) != null) {
distSum -= this.distribution.get(value);
}
this.distribution.put(value, distribution);
distSum += distribution;
}
public int getDistributedRandomNumber() {
double rand = Math.random();
double ratio = 1.0f / distSum;
double tempDist = 0;
for (Integer i : distribution.keySet()) {
tempDist += distribution.get(i);
if (rand / ratio <= tempDist) {
return i;
}
}
return 0;
}
}

View File

@ -0,0 +1,319 @@
package uk.org.mafoo.wordsearch;
import java.util.*;
class GridFactory {
static Random rnd = new Random();
static final int MAX_TRIES = 500;
/* https://www.math.cornell.edu/~mec/2003-2004/cryptography/subs/frequencies.html */
static DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
static {
drng.addNumber(0, 0.0812d); // A
drng.addNumber(1, 0.0149d); // B
drng.addNumber(2, 0.0271d); // C
drng.addNumber(3, 0.0432d); // D
drng.addNumber(4, 0.1202d); // E
drng.addNumber(5, 0.0230d); // F
drng.addNumber(6, 0.0203d); // G
drng.addNumber(7, 0.0592d); // H
drng.addNumber(8, 0.0731d); // I
drng.addNumber(9, 0.0010d); // J
drng.addNumber(10, 0.0069d); // K
drng.addNumber(11, 0.0398d); // L
drng.addNumber(12, 0.0261d); // M
drng.addNumber(13, 0.0695d); // N
drng.addNumber(14, 0.0768d); // O
drng.addNumber(15, 0.0182d); // P
drng.addNumber(16, 0.0011d); // Q
drng.addNumber(17, 0.0602d); // R
drng.addNumber(18, 0.0628d); // S
drng.addNumber(19, 0.0910d); // T
drng.addNumber(20, 0.0288d); // U
drng.addNumber(21, 0.0111d); // V
drng.addNumber(22, 0.0209d); // W
drng.addNumber(23, 0.0017d); // X
drng.addNumber(24, 0.0211d); // Y
drng.addNumber(25, 0.0007d); // Z
}
private static char[] chars = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
private static char getRandomChar() {
return chars[drng.getDistributedRandomNumber()];
}
public static void main(String[] args) {
// Test invocation
char[][] g = makeGrid(new String[] {
"Aberdeenshire",
"Anglesey",
"Angus",
"Antrim",
"Argyll",
"Armagh",
"Ayrshire",
"Banffshire",
"Bedfordshire",
"Berkshire",
"Berwickshire",
"Brecknockshire",
"Buckinghamshire",
"Buteshire",
"Caernarfonshire",
"Caithness",
"Cambridgeshire",
"Cardiganshire",
"Carmarthenshire",
"Cheshire",
"Clackmannanshire",
"Cornwall",
"Cromartyshire",
"Cumberland",
"Denbighshire",
"Derbyshire",
"Devon",
"Dorset",
"Down",
"Dumbartonshire",
"Dumfriesshire",
"Durham",
"East Lothian",
"Essex",
"Fermanagh",
"Fife",
"Flintshire",
"Glamorgan",
"Gloucestershire",
"Hampshire",
"Herefordshire",
"Hertfordshire",
"Huntingdonshire",
"Invernessshire",
"Kent",
"Kincardineshire",
"Kirkcudbrightshire",
"Lanarkshire",
"Lancashire",
"Leicestershire",
"Lincolnshire",
"Londonderry",
"Merionethshire",
"Middlesex",
"Midlothian",
"Monmouthshire",
"Montgomeryshire",
"Morayshire",
"Nairnshire",
"Norfolk",
"Northamptonshire",
"Northumberland",
"Nottinghamshire",
"Orkney",
"Oxfordshire",
"Peeblesshire",
"Pembrokeshire",
"Perthshire",
"Radnorshire",
"Renfrewshire",
"Rossshire",
"Roxburghshire",
"Rutland",
"Selkirkshire",
"Shetland",
"Shropshire",
"Somerset",
"Staffordshire",
"Stirlingshire",
"Suffolk",
"Surrey",
"Sussex",
"Sutherland",
"Tyrone",
"Warwickshire",
"West Lothian",
"Westmorland",
"Wigtownshire",
"Wiltshire",
"Worcestershire",
"Yorkshire",
}, Integer.parseInt(args[0]), Integer.parseInt(args[1]));
dump2d(g);
}
private enum Direction { N, NE, E, SE, S, SW, W, NW; };
private static Direction[] directions = new Direction[] { Direction.N, Direction.NE, Direction.E, Direction.SE, Direction.S, Direction.SW, Direction.W, Direction.NW };
private static Direction getDirection() {
return directions[rnd.nextInt(directions.length-1)];
// return rnd.nextBoolean() ? Direction.E : Direction.S;
}
private static Bounds getBounds(int height, int width, Direction direction, int length) {
// height_min
if(length > height || length > width) {
throw new RuntimeException("Word too long, cannot continue!");
}
Bounds b = new Bounds(0, height, 0, width);
length--; // arrays, duh
if(
direction == Direction.N ||
direction == Direction.NE ||
direction == Direction.NW
) {
b.min_y = length;
}
if(
direction == Direction.W ||
direction == Direction.NW ||
direction == Direction.SW
) {
b.min_x = length;
}
if(
direction == Direction.E ||
direction == Direction.NE ||
direction == Direction.SE
) {
b.max_x = width - length;
}
if(
direction == Direction.S ||
direction == Direction.SW ||
direction == Direction.SE
) {
b.max_y = height - length;
}
assert b.max_x > b.min_x;
assert b.max_y > b.min_y;
assert b.min_x < b.max_x;
assert b.min_y < b.max_y;
return b;
}
private static int move_y(int y, Direction d) {
if(
d == Direction.N ||
d == Direction.NE ||
d == Direction.NW
) {
y--;
} else if (
d == Direction.S ||
d == Direction.SE ||
d == Direction.SW
) {
y++;
}
return y;
}
private static int move_x(int x, Direction d) {
if(
d == Direction.E ||
d == Direction.NE ||
d == Direction.SE
) {
x++;
} else if (
d == Direction.W ||
d == Direction.NW ||
d == Direction.SW
) {
x--;
}
return x;
}
public static char[][] makeGrid(String[] words, int height, int width) {
char[][] grid = new char[height][width];
// Place words at random?
for (String word : words) {
int tries = 0;
while(true) {
try {
grid = placeWord(word, grid);
break;
} catch (CouldNotPlaceWordException e) {
if(tries > MAX_TRIES) {
throw new RuntimeException(e);
}
tries++;
// System.out.println("[" + word + "] Crossed over... retrying");
}
}
}
// Fill rest of grid
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
if (grid[y][x] == Character.UNASSIGNED)
// grid[y][x] = '_';
grid[y][x] = getRandomChar();
}
}
return grid;
}
private static char[][] placeWord(String word, char[][] grid) throws CouldNotPlaceWordException {
Direction direction = getDirection();
Bounds b = getBounds(grid.length, grid[0].length, direction, word.length());
// System.out.println("[" + word + "] bounds: " + b);
int x = rnd.nextInt(b.max_x - b.min_x) + b.min_x;
int y = rnd.nextInt(b.max_y - b.min_y) + b.min_y;
// System.out.println("[" + word + "] Placing @ " + x + "," + y + " going " + direction);
char[][] tempgrid = clone2d(grid);
for( char c : word.toUpperCase().toCharArray() ) {
if(c==' ') continue;
if(grid[y][x] != Character.UNASSIGNED) {
if (grid[y][x] != c) {
throw new CouldNotPlaceWordException();
} else {
// System.out.println("**** SUCCESSFUL CROSSED WORD ****");
}
}
tempgrid[y][x] = c;
x = move_x(x, direction);
y = move_y(y, direction);
}
return tempgrid;
}
private static char[][] clone2d(char[][] source) {
// dump2d(source);
char[][] clone = source.clone();
for(int i=0; i<source.length; i++) {
clone[i] = source[i].clone();
}
// dump2d(clone);
return clone;
}
private static void dump2d(char[][] g) {
for(char[] row : g) {
for(char c : row) {
// System.out.print("|");
System.out.print(c != Character.UNASSIGNED ? c : " ");
}
System.out.println("");
}
}
}