import java.io.*;
import java.math.BigInteger;
import java.util.*;
public class WordSearch {
private char[][] grid;
private ArrayList<String> wordList = new ArrayList<String>(), words = new ArrayList<String>();
private Random random = new Random();
public WordSearch() {grid = new char[0][0];}
public WordSearch(int width, int height) {
if ((width < 0) || (height < 0)) {throw new IllegalArgumentException("WordSearch(int width, int height) -> width and height must be non-negative");}
grid = new char[width][height];
for (int i = 0; i < grid.length; i++) {Arrays.fill(grid[i], '-');}
}
public WordSearch(WordSearch ws) {this.grid = ws.toArray();} //Copy
public WordSearch(WordSearch ws, int width, int height) {
if ((width < 0) || (height < 0)) {throw new IllegalArgumentException("WordSearch(WordSearch ws, int width, int height) -> width and height must be non-negative");}
for (int x = 0; x < Math.min(grid.length, ws.toArray().length); x++) {
grid[x] = Arrays.copyOfRange(ws.toArray()[x], 0, width);
for (int y = ws.toArray()[0].length; y < grid[0].length; y++) {grid[x][y] = '-';} //Forwent the Arrays.fill() method
}
}
private boolean addWord(String word) {return addWord(word, 100);}
private boolean addWord(String word, int retries) {
for (int i = 0; i < retries; i++) {if (addWord(random.nextInt(grid.length), random.nextInt(grid[0].length), random.nextInt(8) + 1, word)) {return true;}}
return false;
}
private boolean addWord(int orientation, String word) {return addWord(orientation, word, 100);}
private boolean addWord(int orientation, String word, int retries) {
for (int i = 0; i < retries; i++) {if (addWord(random.nextInt(grid.length), random.nextInt(grid[0].length), orientation, word)) {return true;}}
return false;
}
private boolean addWord(int x, int y, String word) {
boolean[] orientations = new boolean[8];
Arrays.fill(orientations, false);
int orientation = random.nextInt(8) + 1;
while (!(orientations[1] && orientations[2] && orientations[3] && orientations[4] && orientations[5] && orientations[6] && orientations[7] && orientations[8])) {//Index 0 goes unused
while (orientations[orientation]) {orientation = random.nextInt(8) + 1;}
orientations[orientation] = true;
if (addWord(x, y, orientation, word)) {return true;}
}
return false;
}
//The master addWord method:
private boolean addWord(int x, int y, int orientation, String word) {
word = word.toUpperCase();
if ((x < 0) || (x > grid.length - 1) || (y < 0) || (y > grid.length - 1) || (orientation < 0) || (orientation > 8) || !(word.matches("[A-Z_]*"))) {return false;}
byte xOffset = 0, yOffset = 0;
if (orientation == 0) {orientation = random.nextInt(8) + 1;}
if (orientation == 1) {xOffset = 1; yOffset = 0;} //Horizontal
if (orientation == 2) {xOffset = -1; yOffset = 0;} //Horizontal reversed
if (orientation == 3) {xOffset = 0; yOffset = 1;} //Vertical
if (orientation == 4) {xOffset = 0; yOffset = -1;} //Vertical reversed
if (orientation == 5) {xOffset = -1; yOffset = 1;} //Diagonal left
if (orientation == 6) {xOffset = 1; yOffset = -1;} //Diagonal left reversed
if (orientation == 7) {xOffset = 1; yOffset = 1;} //Diagonal right
if (orientation == 8) {xOffset = -1; yOffset = -1;} //Diagonal right reversed
for (int i = 0; i < word.length(); i++) {if ((x + (i * xOffset) < 0) || (x + (i * xOffset) > grid.length - 1) || (y + (i * yOffset) < 0) || (y + (i * yOffset) > grid[0].length - 1) || ((grid[x + (i * xOffset)][y + (i * yOffset)] != '-') && (grid[x + (i * xOffset)][y + (i * yOffset)] != word.charAt(i)))) {return false;}}
for (int i = 0; i < word.length(); i++) {grid[x + (i * xOffset)][y + (i * yOffset)] = word.charAt(i);}
return true;
}
private int blanks() {
int count = 0;
for (int y = 0; y < grid[0].length; y++) {for (int x = 0; x < grid.length; x++) {if (grid[x][y] == '-') {count++;}}}
return count;
}
public void createPuzzle(String filename, int numWords) throws FileNotFoundException {
readWords(filename);
while ((numWords > 0) && !(wordList.isEmpty())) {
String word = wordList.remove(random.nextInt(wordList.size()));
if ((blanks() >= word.length()) && (addWord(word))) {words.add(word);}
numWords--;
}
System.out.println(this + "\n");
fillRandom();
System.out.println(this + "\n");
System.out.println(words + "\n");
Collections.sort(words);
System.out.println("Alphabetical order:\n" + words);
}
private boolean readWords(String filename) throws FileNotFoundException {
wordList = new ArrayList<String>();
Scanner scanner = new Scanner(new File(filename));
while (scanner.hasNext()) {
String word = scanner.next().toUpperCase();
if ((word.length() >= 3) && (word.matches("[A-Z_]*"))) {wordList.add(word);}
}
return true;
}
public void fillRandom() {for (int y = 0; y < grid[0].length; y++) {for (int x = 0; x < grid.length; x++) {if (grid[x][y] == '-') {grid[x][y] = (char) ('A' + random.nextInt(26));}}}}
public int getHeight() {return grid[0].length;}
public int getWidth() {return grid.length;}
public char[][] toArray() {return grid;}
public String toString() {
String s = "";
for (int y = 0; y < grid[0].length; y++) {
for (int x = 0; x < grid.length; x++) {s += grid[x][y] + " ";}
s = s.trim() + "\n";
}
return s.trim();
}
public static void main(String[] args) throws FileNotFoundException {
String usage = "Usage: java WordSearch width height filename [numWords]\n";
String help = "Type \"java WordSearch\" for help.";
if ((args.length <= 0) || (args.length > 4)) {
System.out.println(usage + "\nfilename: the location of the file containing the words, which are separated by whitespace, to put into the puzzle.");
System.out.println("[numWords] (optional argument): number of words to put into the puzzle (can be greater than the number of words contained in filename). If not specified, put in as many words as possible.");
System.exit(1);
}
if (args.length == 3) {
args = Arrays.copyOf(args, args.length + 1);
args[3] = "none";
}
if (!((args[0] + args[1]).matches("[0-9]+")) || (!(args[3].equals("none")) && !(args[3].matches("[0-9]+")))) {
System.out.println(usage + "\nwidth, height and [numWords] must be non-negative integers.\n" + help);
System.exit(1);
}
try {Scanner scanner = new Scanner(new File(args[2]));}
catch (FileNotFoundException e) {
System.out.println(usage + "\nFilename/path " + "\"" + args[2] + "\"" + " not found.\n" + help);
System.exit(1);
}
int width = Integer.parseInt(args[0]);
int height = Integer.parseInt(args[1]);
int numWords = Integer.MAX_VALUE;
if (!(args[3].equals("none"))) {numWords = Integer.parseInt(args[3]);}
WordSearch ws = new WordSearch(width, height);
ws.createPuzzle(args[2], numWords);
}
}