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);
}
}
}