Computer Science 225
Advanced Programming
Spring 2017, Siena College
WordSearch BlueJ Project
Click here to download a BlueJ project for WordSearch.
WordSearch Source Code
The Java source code for WordSearch is below. Click on a file name to download it.
import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Scanner; import javax.swing.JApplet; /** * A private class to encapsulate a row and column, allowing * them to be stored in data structures. * * @author Jim Teresco * */ class RowCol { /** the row */ protected int row; /** the column */ protected int col; /** * Construct a new RowCol with the given row and column * * @param r the row * @param c the column */ public RowCol(int r, int c) { row = r; col = c; } /** * Determine if two RowCol objects are equal, which is the case only if they * have the same row and column. * * @param o the other RowCol object */ @Override public boolean equals(Object o) { RowCol other = (RowCol)o; return row == other.row && col == other.col; } } /** * Example WordSearch: word search game developed during class. * * The game reads in two required files: one that has the configuration of * the letters on the board (GRID_SIZE lines each of which is a string * of GRID_SIZE characters), and a list of words contained within that * board, oriented horizontally, vertically, or diagonally. * * @author Jim Teresco and the Siena College * Computer Science 225 10:20 class, Spring 2017 * */ public class WordSearch extends JApplet { /** named constant for the size of the square grid of letters */ private static final int GRID_SIZE = 20; /** named constant for the size of the graphics square containing each letter */ private static final int LETTER_SIZE = 20; /** named constant for our font size */ private static final int FONT_SIZE = LETTER_SIZE / 2; /** the grid of letters in which we search */ private String grid[][] = new String[GRID_SIZE][GRID_SIZE]; private ArrayList<String> wordList = new ArrayList<String>(); /** status bar text */ private String status = ""; /** did we just do a first click in an iteration? */ private boolean firstClickHappened; /** where was first click? */ private int click1Row, click1Col; /** collection of cells for the most recent guessed word */ private ArrayList<RowCol> cells = new ArrayList<RowCol>(); /** was that last guess correct? */ private boolean lastGuessCorrect; /** collection of cells for all words already guessed correctly */ private ArrayList<RowCol> foundWords = new ArrayList<RowCol>(); /** * Initialize the applet */ @Override public void init() { // read in the grid of letters from a file "input.txt" // and into our grid array try (Scanner inFile = new Scanner(new File("input.txt"))) { for (int l = 0; l < GRID_SIZE; l++) { String line = inFile.next(); if (line.length() != GRID_SIZE) { System.err.println("input.txt line " + l + " has " + line.length() + " letters, expected " + GRID_SIZE); System.exit(1); } for (int charNum = 0; charNum < GRID_SIZE; charNum++) { grid[l][charNum] = line.substring(charNum, charNum+1); } } inFile.close(); } catch (FileNotFoundException e) { System.err.println("input.txt not found."); System.exit(1); } try (Scanner wordFile = new Scanner(new File("words.txt"))) { while (wordFile.hasNext()) { wordList.add(wordFile.next()); } wordFile.close(); } catch (FileNotFoundException e) { System.err.println("words.txt not found"); System.exit(1); } // We will add our mouse listener as an anonymous inner class. // The MouseAdapter is an abstract class that provides default (empty) // implementations of the methods in MouseListener, MouseMotionListener, // and MouseWheelListener, allowing us to override only those we // actually need. // In this case, we could not "extend MouseAdapter" with the entire class, // since it already extends JApplet and Java does not allow for // multiple inheritance. We could instead implement MouseListener, write // our mouseClicked method as a method of WordSearch, but then we'd need // to provide our own empty implementations of the other required methods // of MouseLister. addMouseListener( new MouseAdapter() { /** * This mouseClicked method handles the main gameplay: a first click to * select the first letter of a guess, and a second click to select the * last letter of a guess, at which point the guess is checked against * the word list. * * @param e mouse event information */ @Override public void mouseClicked(MouseEvent e) { // first make sure the game is not over, determined by an empty word list if (wordList.isEmpty()) return; int x = e.getX(); int y = e.getY(); // make sure we clicked on the grid if (x < 0 || x > (LETTER_SIZE * GRID_SIZE) || y < 0 || y > (LETTER_SIZE * GRID_SIZE)) { status = "Please click on a grid cell!"; repaint(); return; } // convert x and y coordinates to the row and column in the grid int row = y / LETTER_SIZE; int col = x / LETTER_SIZE; // how we handle the click depends on the context if (firstClickHappened) { // this means we already did the first click, so process the second click // which will be on a cell where we want to select the last letter of the // guessed word // for next time... firstClickHappened = false; // our procedure here is to build up a guess in the string guess, and // a list of positions occupied by those in the cells ArrayList String guess = ""; cells.clear(); // there are several cases covering the horizontal, vertical, and diagonal // there are also likely more elegant ways of doing all these checks // horizontal if (row == click1Row) { // forward (left to right) if (click1Col < col) { for (int colPos = click1Col; colPos <= col; colPos++) { guess += grid[row][colPos]; cells.add(new RowCol(row, colPos)); } } // backward (right to left) else { for (int colPos = click1Col; colPos >= col; colPos--) { guess += grid[row][colPos]; cells.add(new RowCol(row, colPos)); } } } // vertical if (col == click1Col) { // down if (click1Row < row) { for (int rowPos = click1Row; rowPos <= row; rowPos++) { guess += grid[rowPos][col]; cells.add(new RowCol(rowPos, col)); } } // up else { for (int rowPos = click1Row; rowPos >= row; rowPos--) { guess += grid[rowPos][col]; cells.add(new RowCol(rowPos, col)); } } } // off diagonal: \ if ((col - click1Col) == (row - click1Row)) { // up and left if (col < click1Col) { for (int offset = 0; offset <= click1Col - col; offset++) { guess += grid[click1Row - offset][click1Col - offset]; cells.add(new RowCol(click1Row - offset, click1Col - offset)); } } // down and right else { for (int offset = 0; offset <= col - click1Col; offset++) { guess += grid[click1Row + offset][click1Col + offset]; cells.add(new RowCol(click1Row + offset, click1Col + offset)); } } } // main diagonal: / if ((col - click1Col) == (click1Row - row)) { // down and left if (col < click1Col) { for (int offset = 0; offset <= click1Col - col; offset++) { guess += grid[click1Row + offset][click1Col - offset]; cells.add(new RowCol(click1Row + offset, click1Col - offset)); } } // up and right else { for (int offset = 0; offset <= col - click1Col; offset++) { guess += grid[click1Row - offset][click1Col + offset]; cells.add(new RowCol(click1Row - offset, click1Col + offset)); } } } if (guess.equals("")) { status = "Choose a position in the same row, column, or diagonal."; firstClickHappened = true; } else { status = "You guessed: " + guess; // did we find it? if (wordList.contains(guess)) { status += " and it's a match!"; foundWords.addAll(cells); wordList.remove(guess); lastGuessCorrect = true; } else { status += " which is not one of the words..."; lastGuessCorrect = false; } } } else { firstClickHappened = true; click1Row = row; click1Col = col; cells.clear(); status = "Choose the position of the last letter of your guess."; } repaint(); } }); firstClickHappened = false; } /** * repaint the graphics area for our applet * * @param g the Graphics object on which we will draw */ @Override public void paint(Graphics g) { // "erase" anything that's on the graphics area from earlier g.setColor(Color.WHITE); g.fillRect(0, 0, getWidth(), getHeight()); // draw grid of letters g.setColor(Color.BLACK); Font font = new Font("UTF-8", Font.PLAIN, FONT_SIZE); for (int row = 0; row < GRID_SIZE; row++) { for (int col = 0; col < GRID_SIZE; col++) { // highlight grid cells for previously found words if (foundWords.contains(new RowCol(row, col))) { g.setColor(Color.YELLOW); g.fillRect(LETTER_SIZE * col, LETTER_SIZE * row, LETTER_SIZE, LETTER_SIZE); g.setColor(Color.BLACK); } // highlight grid cells for most recent selected word, green if correct, red if not if (cells.contains(new RowCol(row, col))) { if (lastGuessCorrect) { g.setColor(Color.GREEN); } else { g.setColor(Color.RED); } g.fillRect(LETTER_SIZE * col, LETTER_SIZE * row, LETTER_SIZE, LETTER_SIZE); g.setColor(Color.BLACK); } // highlight grid cell for first click if (firstClickHappened && (row == click1Row) && (col == click1Col)) { Color pink = new Color(255, 128, 128); g.setColor(pink); g.fillRect(LETTER_SIZE * col, LETTER_SIZE * row, LETTER_SIZE, LETTER_SIZE); g.setColor(Color.BLACK); } g.drawRect(LETTER_SIZE * col, LETTER_SIZE * row, LETTER_SIZE, LETTER_SIZE); g.drawString(grid[row][col], LETTER_SIZE * col + (LETTER_SIZE - FONT_SIZE) / 2, LETTER_SIZE * row + LETTER_SIZE - FONT_SIZE / 2); } } // draw words to search int startY = LETTER_SIZE * GRID_SIZE + FONT_SIZE; for (String word : wordList) { g.drawString(word, 0, startY); startY += FONT_SIZE * 3 / 2; } // draw our current game status g.drawString(status, 0, getHeight() - 2*FONT_SIZE); // if the game is over (empty word list), put that message up if (wordList.isEmpty()) { g.setColor(Color.BLUE); g.drawString("You found all the words! Game over.", 0, startY); } } }