diff options
author | Jérémy Zurcher <jeremy@asynk.ch> | 2014-05-14 16:18:47 +0200 |
---|---|---|
committer | Jérémy Zurcher <jeremy@asynk.ch> | 2014-05-14 16:18:47 +0200 |
commit | ebe40f954e5caa034f0cbffb68ac85f13395ec6b (patch) | |
tree | cebf529f2a5f653f9a63318b5504587d5893b22f /Algorithms/Part-II/4-Boggle/BoggleSolverDicho.java | |
parent | 2ab59b85eeab78ef54570c6ae7c451ad142012b9 (diff) | |
download | coursera-ebe40f954e5caa034f0cbffb68ac85f13395ec6b.zip coursera-ebe40f954e5caa034f0cbffb68ac85f13395ec6b.tar.gz |
Algorithms-II : 4-Boggle: implementationalgs-II
Diffstat (limited to 'Algorithms/Part-II/4-Boggle/BoggleSolverDicho.java')
-rw-r--r-- | Algorithms/Part-II/4-Boggle/BoggleSolverDicho.java | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/Algorithms/Part-II/4-Boggle/BoggleSolverDicho.java b/Algorithms/Part-II/4-Boggle/BoggleSolverDicho.java new file mode 100644 index 0000000..23a645a --- /dev/null +++ b/Algorithms/Part-II/4-Boggle/BoggleSolverDicho.java @@ -0,0 +1,305 @@ +/* vim: set expandtab tabstop=4 shiftwidth=4 : */ + +import java.util.Set; +import java.util.HashSet; +import java.util.Arrays; + +public class BoggleSolverDicho +{ + + private class BoggleDictState + { + private String s; + private int idx, from, to; + private boolean isWord; + + public BoggleDictState(int from, int to) + { + this.s = ""; + this.idx = -1; + this.from = from; + this.to = to; + this.isWord = false; + } + + public BoggleDictState(String s, int idx, int from, int to, + boolean isWord) + { + this.s = s; + this.idx = idx; + this.from = from; + this.to = to; + this.isWord = isWord; + } + + public String s() { return s; } + public int idx() { return idx; } + public int from() { return from; } + public int to() { return to; } + public boolean isWord() { return isWord; } + public int n() { return (to - from + 1); } + + public String toString(String[] words) + { + String ret = s + "(" + idx + ") " + isWord + " " + + " [" + from + ";" + to + "](" + n()+") "; + + if (from > 0) ret += words[from - 1]; + ret += " ["+words[from]+"..."+words[to]+"] "; + if (to < (words.length - 1)) ret += words[to + 1]; + + return ret; + } + } + + private class BoggleDict + { + private String[] words; + + public BoggleDict(String[] words) + { + this.words = Arrays.copyOf(words, words.length); + } + + public int size() + { + return words.length; + } + + public boolean exists(String word) { + if (word.isEmpty()) return false; + + BoggleDictState st = new BoggleDictState(0, (size() - 1)); + for (int i = 0; i < word.length(); i++) { + st = filter(word.charAt(i), st); + if (st == null) return false; + } + + return st.isWord(); + } + + private BoggleDictState filter(char c, BoggleDictState st) + { + int idx = st.idx() + 1; + int from = st.from(); + int to = st.to(); + int n = st.n(); + + if (words[from].length() <= idx) { + if (n == 1) return null; + from++; + } + + boolean fromOk = (words[from].charAt(idx) == c); + boolean toOk = (words[to].charAt(idx) == c); + + if (!fromOk && (n == 1)) return null; + + // if (n < 200) { + // // lower bound + // if (!fromOk) { + // for (int i = from; i <= to; i++) { + // if (words[i].charAt(idx) == c) { + // fromOk = true; + // from = i; + // break; + // } + // } + // if (!fromOk) return null; + // } + // // upper bound + // if (!toOk) { + // for (int i = to; i >= from; i--) { + // if (words[i].charAt(idx) == c) { + // toOk = true; + // to = i; + // break; + // } + // } + // if (!toOk) return null; + // } + // } + // lower bound + if (!fromOk) { + int tob = to; + + int mid = (from + tob) / 2; + while (mid != from) { + + int diff = words[mid].charAt(idx) - c; + + if (diff > 0) { + to = mid; + tob = mid; + } else if (diff < 0) + from = mid; + else + tob = mid; + + mid = (tob + from) / 2; + } + if (!(words[from].charAt(idx) == c)) { + if (words[tob].charAt(idx) == c) from = tob; + else return null; + } + } + + // upper bound + if (!toOk) { + int fromb = from; + int mid = (fromb + to) / 2; + while (mid != fromb) { + + int diff = words[mid].charAt(idx) - c; + + if (diff <= 0) + fromb = mid; + else + to = mid; + + mid = (fromb + to) / 2; + } + if (!(words[to].charAt(idx) == c)) { + if (words[fromb].charAt(idx) == c) to = fromb; + else return null; + } + } + + boolean isWord = ((idx > 1) && ((words[from].length() - 1) == idx)); + + return new BoggleDictState((st.s() + c), idx, from, to, isWord); + } + } + + private int cols, rows; + private BoggleDict dict; + private BoggleBoard board; + private boolean[] visited; + private Set<String> result; + + // assume each word in the dictionary contains only [A-Z] + public BoggleSolverDicho(String[] dictionary) + { + dict = new BoggleDict(dictionary); + } + + // Returns the set of all valid words in the given Boggle board + public Iterable<String> getAllValidWords(BoggleBoard b) + { + this.board = b; + this.cols = board.cols(); + this.rows = board.rows(); + this.result = new HashSet<String>(); + + BoggleDictState emptyState = new BoggleDictState(0, (dict.size() - 1)); + for (int r = 0; r < this.rows; r++) { + for (int c = 0; c < this.cols; c++) { + this.visited = new boolean[this.rows * this.cols]; + explore(r, c, emptyState); + } + } + + return result; + } + + // + private void explore(int r, int c, BoggleDictState current) + { + if ((r < 0) || (r >= rows) || (c < 0) || (c >= cols)) return; + + int visitedIdx = (r * this.cols) + c; + if (visited[visitedIdx]) return; + + char ch = board.getLetter(r, c); + BoggleDictState next = dict.filter(ch, current); + if (next == null) return; + if (ch == 'Q') { + next = dict.filter('U', next); + if (next == null) return; + } + + if (next.isWord()) result.add(next.s()); + + visited[visitedIdx] = true; + + explore((r - 1), (c - 1), next); + explore((r - 1), c, next); + explore((r - 1), (c + 1), next); + explore(r, (c - 1), next); + explore(r, (c + 1), next); + explore((r + 1), (c - 1), next); + explore((r + 1), c, next); + explore((r + 1), (c + 1), next); + + visited[visitedIdx] = false; + } + + // Returns the score if it is in the dictionary, zero otherwise. + // assume the word contains only [A-Z] + public int scoreOf(String word) + { + if (!dict.exists(word)) return 0; + + int l = word.length(); + if (l < 3) { + return 0; + } else if (l < 5) { + return 1; + } else if (l < 6) { + return 2; + } else if (l < 7) { + return 3; + } else if (l < 8) { + return 5; + } else { + return 11; + } + } + + public static void main(String[] args) + { + if (args[0].equals("timing")) { + In in = new In("./data/dictionary-yawl.txt"); + String[] dictionary = in.readAllStrings(); + + Stopwatch w = new Stopwatch(); + BoggleSolver solver = new BoggleSolver(dictionary); + double dt = +w.elapsedTime(); + System.out.println("construction : "+dt); + + String s = "board-pneumonoultramicroscopicsilicovolcanoconiosis.txt"; + BoggleBoard []boards = new BoggleBoard[5]; + boards[0] = new BoggleBoard("./data/board-points4527.txt"); + boards[1] = new BoggleBoard("./data/board-points13464.txt"); + boards[2] = new BoggleBoard("./data/board-points4410.txt"); + boards[3] = new BoggleBoard("./data/board-points1250.txt"); + boards[4] = new BoggleBoard("./data/board-points1500.txt"); + // boards[1] = new BoggleBoard("./data/board-rotavator.txt"); + // boards[2] = new BoggleBoard("./data/board-16q.txt"); + // boards[4] = new BoggleBoard("./data/" + s); + + + for (int t = 0; t < 5; t++) { + w = new Stopwatch(); + for (int i = 0; i < 3000; i++) { + solver.getAllValidWords(boards[i % 5]); + } + dt = +w.elapsedTime(); + System.out.println("search time : "+dt); + } + } else { + In in = new In(args[0]); + String[] dictionary = in.readAllStrings(); + BoggleSolverDicho solver = new BoggleSolverDicho(dictionary); + BoggleBoard board = new BoggleBoard(args[1]); + int score = 0; + for (String word : solver.getAllValidWords(board)) + { + StdOut.println(word); + score += solver.scoreOf(word); + } + StdOut.println("Score = " + score); + StdOut.println("Score = " + solver.scoreOf("REQUEST")); + } + } +} |