commit 865b8df4060be409b9484b8814f52872f996dcb3 Author: foo Date: Sat Dec 17 21:45:03 2016 +0000 initial working import! diff --git a/uk/org/mafoo/wordsearch/Bounds.java b/uk/org/mafoo/wordsearch/Bounds.java new file mode 100755 index 0000000..e045aba --- /dev/null +++ b/uk/org/mafoo/wordsearch/Bounds.java @@ -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 +"]"; + } +} \ No newline at end of file diff --git a/uk/org/mafoo/wordsearch/CouldNotPlaceWordException.java b/uk/org/mafoo/wordsearch/CouldNotPlaceWordException.java new file mode 100755 index 0000000..cb10aa7 --- /dev/null +++ b/uk/org/mafoo/wordsearch/CouldNotPlaceWordException.java @@ -0,0 +1,7 @@ +package uk.org.mafoo.wordsearch; + +class CouldNotPlaceWordException extends Exception { + protected CouldNotPlaceWordException() { + + } +} \ No newline at end of file diff --git a/uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java b/uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java new file mode 100755 index 0000000..9230850 --- /dev/null +++ b/uk/org/mafoo/wordsearch/DistributedRandomNumberGenerator.java @@ -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 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; + } + +} diff --git a/uk/org/mafoo/wordsearch/GridFactory.java b/uk/org/mafoo/wordsearch/GridFactory.java new file mode 100755 index 0000000..469fbd6 --- /dev/null +++ b/uk/org/mafoo/wordsearch/GridFactory.java @@ -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