September 18, 2005:
September 23, 2005:
October 1, 2005:
October 6, 2005:
October 12, 2005:
October 27, 2005:
October 30, 2005:
November 1, 2005:
November 2, 2005:
November 10, 2005:
More on Listening for Keys in a GUI
November 18, 2005:
Even More on Listening for Keys in a GUI
November 24, 2005:
February 15, 2006:
Shape Tools for Intersections Etc
March 23, 2006:
Ken Eimer Pong Game ... The Road to Gravity
The plan or syllabus for the Freshman Honors Seminar in Computer & Information Science as a Word document or PDF document.
Access to the Java Power Tools.
The main JPT site: http://www.ccs.neu.edu/jpt/
The JPT 2.4.0 site: http://www.ccs.neu.edu/jpt/jpt_2_4/
The JPT 2.4.0 library file jpt.jar: http://www.ccs.neu.edu/jpt/jpt_2_4/lib/jpt.jar
The JPT 2.4.0 javadocs: http://www.ccs.neu.edu/jpt/jpt_2_4/docs/
The JPT 2.4.0 annotated source code: http://www.ccs.neu.edu/jpt/jpt_2_4/src/
The Methods.java file that may be used as a template for the Java Power Framework.
The cascading style sheet for this web site: fhs.css.
The methods file
Sample1.java
illustrates seven simple uses of JPT and the Java Power Framework.
Please load this file into Eclipse with JPT installed and run the various
methods. Then read the comments below on each method.
Our goal is for you to read the code and play detective. See how much of the code you can understand or at least guess as to the meaning. Look for patterns. Note whatever is puzzling. We will discuss such things in class.
In PrintThing, we illustrate how to print simple text
output in the JPT console window.
In DemandSumInConsole and RequestSumInConsole,
we compare the input-output patterns for the two paradigms supported by
JPT.
In the demand paradigm, the user must supply valid data of the
type expected or else exit the entire program. In the example, in
which a sum of double precision numbers is being calculated, the user
must supply a valid double or else the system will prompt for the
input again. This requires deciding on a clean exit strategy.
In the example, we choose to interpret the input of 0 as
a summand as the user signal to cleanly exit the calculation.
In the request paradigm, the user must supply valid data of the
type expected or else press return on an empty line to signal that
the task is done. Thus, a clean exit strategy is built-in.
The code uses a Cancelled Exception internally when the
user presses return on a empty line and thus the code must look for
this exception with a try-catch that handles the user's
desire to exit.
Please compare the if-else structure in the demand
code with the try-catch structure in the request
code. You will see that the code is quite similar.
In EvalMathExpression, we illustrate two important
features of JPT. First, if a simple public method in a JPF methods
class has parameters and/or a return value, then JPF will build the
GUI to obtain the parameters and display the return. Second, all
text input in JPT that is to be converted into numerical data is
automatically passed to a parser that reads and interprets
mathematical expressions. These features are illustrated in the
following screen snapshot that shows the evaluation of
sqrt(5) + pi + e
In RectangleAndCircle and FilledRectangleAndCircle,
we illustrate how to install shapes into the graphics window of the automatic
JPF graphical user interface.
In RectangleAndCircle, we construct two shapes and add them as
Paintable objects to the window. These shapes are technically
not yet Paintable so the addPaintable method wraps
them in a suitable manner to display them with black strokes of thickness 2.
In FilledRectangleAndCircle, we construct two shapes and then
wrap them explicitly ourselves. This allows us more options. For the
first shape, we specify FILL rather than the default DRAW and specify the
fill color as green. For the second shape, we specify FILL_DRAW with the
fill color as violet; since the draw color and stroke are omitted, these
default to black strokes of thickness 2.
Here is a screen snapshot of FilledRectangleAndCircle.
In ShowRandomCards, we have a somewhat more sophisticated example
so we do not expect you to understand everything immediately. Here you should try
to read the code and do some detective work to see how much you can figure out
from the information in the program.
The code begins by reading the images of cards in a card deck including two card backs and two jokers. Since there are 56 total images, you will notice a delay as the cards are read from the web. Below, we give the links to the directory of the images and the text file that controls the order in which the images are read. You may check out this data directly.
Here is a link to the JFitz card image directory on the JPT site.
Here is a link to the imagelist.txt file that lists the image files in the JFitz card image directory on the JPT site in the order in which the images will be read. You will see that the suits are read in the order Hearts, Diamonds, Spades, and Clubs and within each suit the order will be Ace, 2, ... 10, Jack, Queen, King. The 4 additional cards in the list are a black vertical card back, a red vertical card back, a black joker, and a red joker. You will notice that there are additional images in the directory that we choose not to put in imagelist.txt.
After reading the images, the code uses ProbStatTools to create a
random permutation so that the cards will be displayed in random order. The code
also uses MathUtilities to move each card to a random card location.
Here is a screen snapshot of ShowRandomCards.
You will notice that if you click ShowRandomCards multiple times,
the later images will display quickly due to file-IO caching done by Java.
The methods file
Sample2.java
The vanilla sum panel file
SumPanel.java
The sum panel file using the Halo wrapper
SumPanelWithHalo.java
Before the detailed discussion, we will show screen snapshots of the two variations of the sum panel: vanilla and with halo.
|
|
| Vanilla Sum Panel | Sum Panel With Halo |
You can see immediately that the Sum Panel With Halo frame looks less crowded. We will discuss later why this is so.
Now let us discuss the code starting with SumPanel. The first
block of code introduces the 5 text fields for the data
x1, x2, x3, x4, and the total.
private static int width = TextFieldView.getSampleWidth(20, '0');
private TextFieldView view1 = new TextFieldView("0", width);
private TextFieldView view2 = new TextFieldView("0", width);
private TextFieldView view3 = new TextFieldView("0", width);
private TextFieldView view4 = new TextFieldView("0", width);
private TextFieldView total = new TextFieldView("0", width);
A TextFieldView is a JPT class based on Java’s class
JTextField and its main purpose is to add robust I/O for
multiple data types. As you can see, each text field is initialized to
hold one character 0 and to have the same width. The
width is computed first by a method that returns the width of a string
with 20 zeroes. In other words, the text fields are designed to hold
20 digits.
The next block of code makes an object that encapsulates the behavior we wish to perform, namely, to sum the text fields x1, x2, x3, x4, and then place the result into the text field total.
private SimpleAction sumAction =
new SimpleAction("Sum Data") {
public void perform() { sum(); }
};
At first this code looks peculiar. It creates a SimpleAction
object that is given a string name Sum Data and is also given a
method definition, namely, the perform method is defined and
its definition is tantamount to calling the sum method defined
later in the class. Why this roundabout definition structure?
Our goal is to define the button Sum Data that you see in each of the snapshots. A button must have a label and a behavior to perform when it is clicked by the user. We know both of these. We want the label to be Sum Data and the behavior to be the sum method. The problem is that Java prohibits passing method names directly as arguments to anything so there is no direct way to tell a button what it should do! In some ways, this is an unfortunate restriction made by the designers of Java but we must all live with it. The solution to this dilemma is that we must construct an object that is expected to contain a method with a standard name, in this case, perform, and we implement perform by a one line call to the method sum that we really want to use.
At this point, Java takes over since it has a standard way to construct a
button using an object of the general category of Action.
We will see in a moment that JPT automates the final step from action to
button.
The next blocks of code concern building the graphical user interface or GUI. You will notice that the 5 text fields have 5 corresponding labels and together these form a table with 5 rows and 2 columns. You can also see that the button is centered below this 5-by-2 table. We build the GUI in two steps. We make a 5-by-2 table object for the labels and text fields and then we insert this table into a vertical table with the action/button below. Here is the code.
private Object[][] dataStuff =
new Object[][] {
{ "x1", view1 },
{ "x2", view2 },
{ "x3", view3 },
{ "x4", view4 },
{ "total", total }
};
private TablePanel dataPanel =
new TablePanel(
dataStuff, 10, 10, WEST);
private Object[] mainStuff =
new Object[] { dataPanel, sumAction };
private TablePanel mainPanel =
new TablePanel(
mainStuff, VERTICAL, 10, 10, CENTER);
The first step in making the 5-by-2 table is to create a 2-dimensional
array with 5 rows and 2 entries per row. Each row consists of a label
and its corresponding view. This is what is done in the definition of
dataStuff. This is the raw material for building the
5-by-2 table.
The next step is to create the table dataTable using the
data dataStuff. The constructor specifies the data,
a horizontal and vertical gap between cells of 10, and an alignment of
WEST which means that within cells objects are pushed
towards the west or left edge.
The next step is to combine the dataTable with the action
sumAction to make a second data array in preparation for
making the outer table. This is what is done in the definition of the
1-dimensional array mainStuff.
Finally, we create mainTable using mainStuff.
Since the array is 1-dimensional, we must specify a direction
HORIZONTAL or VERTICAL.
We choose VERTICAL in this case.
For alignment, we specify CENTER which is how
we get the button to be centered under the 5-by-2 table.
One powerful feature of TablePanel is that it can accept
general objects such as String (the labels) or
Action (sumAction) and figure out how to
make them into the appropriate GUI components. Thus
sumAction is used to automatically construct the button
that uses the action name for the button label and the perform
method for the button behavior.
The next step is the constructor for the SumPanel. The
constructor completes any initialization steps that cannot be
conveniently done in the earlier member data definition steps. Here
is the constructor.
public SumPanel() {
add(mainPanel);
addListeners();
frame("Sum Panel");
}
To understand this, let us also look at the class header.
public class SumPanel extends TablePanel
This shows that SumPanel is also a TablePanel.
The first line of the constructor says to take mainPanel
and make it the single component within the SumPanel which
acts as a wrapper. This style of building all the pieces of the GUI in
the data definitions and then having one add statement to
wrap things up is a very common idiom in JPT code.
The second line of the constructor calls the addListeners()
method that we will describe below.
The third line of the constructor says to take the SumPanel
and place it in a frame, that is, a full-fledged window on the
screen that has Sum Panel as its title. This frame is
centered on the screen by default. We call the process of taking a
panel and putting it into a frame self actualization since it
avoids the traditional Java step of separately constructing the frame
and inserting the panel into its so-called content pane.
Let us finally look at the methods in this class of which there are only
two. The first method, sum(), does the algorithmic work of
the class since it implements the behavior in sumAction.
private void sum() {
double x1 = view1.demandDouble();
double x2 = view2.demandDouble();
double x3 = view3.demandDouble();
double x4 = view4.demandDouble();
double x = x1 + x2 + x3 + x4;
total.setViewState(x + "");
}
In the first four lines of sum(), we obtain the four values
to be summed. The method demandDouble() of the
TextFieldView class is used. This method insists that the user
provide valid numeric data and will use error dialog boxes until any
mistakes are fixed. This is an example of a method provided in
TextFieldView that is not available in Java base class
JTextField.
The next line does the mathematics of summation.
The final line converts the number x to a String
via the Java idiom x + "" and then places the
String into the total text field using the method
setViewState which is also defined in
TextFieldView.
The second and last method, addListeners(), is present for
the convenience of the user. A text field will listen for a
special event, namely, if the user presses the return-key while the
cursor is in the text field. If this event happens then any action
that has been specified via addActionListener will be done.
Thus, in this case, the summation action can also be triggered if the
user presses return in one of the first four text fields. This means
that the user does not actually have to click the Sum Data
button.
private void addListeners() {
view1.addActionListener(sumAction);
view2.addActionListener(sumAction);
view3.addActionListener(sumAction);
view4.addActionListener(sumAction);
}
The method addActionListener is inherited by
TextFieldView from the Java base class JTextField.
We now explain what a Halo does and why it is used. A
Halo is a wrapper panel that surrounds another panel and
provides a small border. Its primary use in JPT is to provide focus
if a user makes an input error. By default, if an error occurs in a
TextFieldView, JPT will highlight the smallest panel that
surrounds the text field. This can sometimes be problematic. In the
case of the SumPanel, the smallest panel surrounding any
of the text fields is the 5-by-2 table panel. Thus, no matter where
the error occurs, the entire 5-by-2 panel is highlighted. This is not
so nice for the user.
The Halo class solves this problem by providing a small
panel to wrap around what is inside it so error highlighting will be
focused. Here is the change in the code to construct the array
dataStuff to add the necessary Halo
wrappers.
private Object[][] dataStuff =
new Object[][] {
{ "x1", new Halo(view1) },
{ "x2", new Halo(view2) },
{ "x3", new Halo(view3) },
{ "x4", new Halo(view4) },
{ "total", new Halo(total) }
};
In this code, each Halo uses a default border size of
2 pixels all around each text field.
A Halo may also be used to provide an overall border
to a panel. Here is the change to the code that accomplishes this.
add(new Halo(mainPanel, 10, 10));
Here we use a larger border of 10 pixels all around the main panel.
With this, you have all of the changes between SumPanel
and SumPanelWithHalo.
Here is the code for the Shape Editor demo which is on the JPT 2.4.0 site.
Most of the first student programs have been incorporated into the JPF Methods class. Two auxiliary classes were built by Jonathan Pelc and Michael Thomas. The most ambitious first program is by Michael Thomas.
The names of methods and classes have been modified to place the name of the student in front of the original name given by the student.
The methods file
FHS_Methods_01.java
The file
Pelc_FirstCode.java
The file
Thomas_ListSearcher.java
At the time that JPT 2.3.0 was released, a document was written that was intended to be the first chapter of a “JPT Book”. This project was not continued but that chapter is still useful as an introduction to JPT.
The code associated with the “JPT Book” can now be simplified further
using the Paintable interface and the ShapePaintable class
but I felt that it would still be useful for you to see the original sample code and
first chapter document.
A copy of the “JPT Book” first chapter will be distributed in class.
Here is the link to the JPT Book and to all of the original sample code. You may download the files individually, in a zip file, or as a Windows self-extracting archive. Alternatively, you may wish to build the files yourself, one-by-one, and by typing the code, fixing mistakes, and doing experiments make the ideas more your own.
Below, I give links to a revised version of the Circle Samples that use the
Paintable interface and the ShapePaintable class. There is no
updated document that explains the changes in detail. If you compare these new files
with the older versions, you will see that the structure that sets up the GUI is
mostly the same but that there are changes in the geometric objects that define the
circles and lines and in the code that paints the circles and lines onto the graphics
window.
The methods file
SampleCode01.java
The Circle Sample version 0 file
CircleSample0.java
The Circle Sample version 1 file
CircleSample1.java
The Circle Sample version 2 file
CircleSample2.java
The Circle Sample version 3 file
CircleSample3.java
The Circle Sample version 4 file
CircleSample4.java
The Circle Sample version 5 file
CircleSample5.java
The Circle Sample version 6 file
CircleSample6.java
All files
Circle_Samples_Revised.zip
in a zip file.
All files
Circle_Samples_Revised.exe
in a Windows self-extracting archive.
The names of methods and/or classes may have been modified to place the name of the student in front of the original name given by the student.
The methods file
FHS_Methods_02.java
The file
McLaughlin_Encode.java
The file
Morgano_StringAdder.java
The file
Reed_Panel.java
The file
Sawyer_Panel.java
The file
Scullane_Panel.java
The Tic Tac Toe game is elementary and so provides a simple setting in which to illustrate some additional ideas in GUI building. Before further discussion, let us show two screen snapshots from the demo program.
In the first screen snapshot, player X has won the game and the winning sequence is highlighted in yellow. In the second screen snapshot, the game has been played to a tie since neither X nor O has won and no more moves are possible.
The game uses the concept of a tile that has a size, a painted object, and a
background color. There are actually three kinds of tile: the blank tile that just
paints the background, the X tile, and the O tile. Notice that the same thing may
be painted on several tiles. This distinction is important and is reflected in the
code. The three things that are painted (blank, X, O) are Paintable
objects that remain the same throughout the program. The 9 tile objects that are
visible in the GUI are TileBox objects that can change their internal
Paintable object and so can change what they display. In particular,
as long as the game is not over, if a blank tile is clicked then it will change to
an X tile or an O tile depending on what player has the next move. Technically,
the tile does not change its identity only its Paintable contents.
The tiles are arranged in a 3-by-3 grid using a PaintableSequence. The
initialization code creates a 3-by-3 array of TileBox objects each with
a blank as its contents and burlywood as its background color. Using the move command,
these tiles are geometrically positioned before being added to the seqeunce.
The PaintableSequence is in turn placed in a PaintableComponent
which is an extension of the Java JComponent class designed to hold objects
that are Paintable. A PaintableComponent is also set up to
handle assorted mouse actions.
The mouse code that controls the game is quite simple. When the mouse is clicked, several checks are made. If the game is over or if the mouse has not hit a blank tile, then the code does nothing. On the other hand, if the mouse has hit a blank tile, then the contents of that tile is changed to an X or O depending on what player is next and then the next player is switched to its opposite. After each click, a check is made to see if the game has been won or if no more moves are possible.
In effect, one can think of the tile grid as a complex button that responds
to mouse clicks in a subtle fashion depending on what particular tile is clicked. This
illustrates how complex behavior can be coded in a rather simple fashion.
The file
TicTacToe.java
There is a demo program that gives a visual display of the bits
in an int versus a float (32 bits)
and a long versus a double (64 bits).
To try this demo program as an applet, go to:
This demo program may be helpful as you try to learn the material in the Discrete Structures course.
The names of methods and/or classes may have been modified to place the name of the student in front of the original name given by the student.
A main program has been added to each class that creates a frame in its constructor. Thus such classes can be launched as standalone programs. For convenience, we also include a Methods class to launch all programs from one place.
Code additions or bug fixes have been noted in comments.
The methods file
FHS_Methods_03.java
The file
Costa_Panel.java
The file
Costa_BlackJack.java
The file
Goyne_Card.java
The file
Goyne_Cardgame.java
The file
Janulawicz_GCDLCM.java
The file
Leinung_Quadratic_Dots.java
The file
Leinung_QuadraticFormula.java
The file
Pelc_Math_Maker.java
The file
Sawyer_Checkers.java
The file
Scullane_mod.java
The file
Scullane_SumPanel.java
The file
Thomas_CardTricks.java
This set of sample files shows how to create:
IntList that enables efficient
append operations.IntListNode that holds
one integer and a reference to the next node in the list.IntListIterator that traverses a
“list of integer”.Primes that generates lists of integer primes.The IntList class is based on the IntListNode class
that creates a chain of nodes each with one int together with a
reference to the next node in the chain. An IntList maintains 2
objects of type IntListNode: the head node points to
the start of the chain of nodes and the tail node points to the
last node of the chain. Append is simple because the operation is done using the
tail node. Once the append operation is complete, the tail
node reference is replaced by a reference to the newly appended node.
The IntListIterator class arranges to step through an
IntList class item by item. Each iterator can be used precisely
once. To iterate again, create a new IntListIterator object.
The Primes class has two public static methods that do
the following operations:
IntList getPrimesUpTo(int n) returns a list of
all primes up to and including n.IntList getPrimesList(int size) returns a list with
size items that contains the first
size primes.Here are the files:
The file
IntList.java
The file
IntListNode.java
The file
IntListIterator.java
The file
Primes.java
The methods file
Methods.java
A zip file with all of the above files
Primes.zip
Below is a screen snapshot of a test of
getPrimesUpTo(100):
This set of demo programs solves the same “list of integer” problem as the previous demo but with more sophisticated coding. In this version, the node contains an array of integer of some fixed capacity that may be specified at construction. In this way, many int’s may be added to the node before it is necessary to construct an entirely new node. This reduces the time needed for “new” operations and the space overhead of many small node objects.
This code is rather more advanced than the previous demo and is placed here for those who may wish to investigate a “theme and variations”, that is, who enjoy seeing the same problem solved in two ways.
Here are the files:
The file
IntArrayList.java
The file
IntArrayListNode.java
The file
IntArrayListIterator.java
The file
Primes.java
The methods file
Methods.java
A zip file with all of the above files
Primes2.zip
The demo program illustrates how to set up a key listener for
a BufferedPanel window.
In the screen snapshot above, the red square was moved from its initial pixel position of (100,100) to the position shown (120,105) entirely using the keyboard. The arrow keys are enabled to move the square by 1 pixel in the corresponding direction. If the shift key is down when the arrow key is pressed then the square jumps by 10 pixels rather than by 1 pixel. Thus, the square was moved by doing the following operations. Press shift; click right arrow twice; release shift; click down arrow five times.
A BufferedPanel comes with a KeyActionAdapter
installed on its inner panel just as it comes with a corresponding
MouseActionAdapter. However, before the
KeyActionAdapter can do its job as a KeyListener,
additional steps must be taken. The issue is that Java must know what
component should listen for the key events. This is not so obvious since
a key does not point to a component directly in the way that a mouse click
does. The way that Java handles this ambiguity is to give a key event to
the current component that has “focus”, that is, the component
that is the center of attention.
By default, JPT does not initialize the inner panel to have focus since
normally a BufferedPanel does not respond to key events. So,
this initialization must be done. Then, it is also necessary to make sure
that the inner panel actually has focus. Here is how these steps are done.
First, it is helpful to name the inner panel of the
BufferedPanel.
public static int SIZE = 400;
BufferedPanel window = new BufferedPanel(SIZE, SIZE);
DisplayPanel inner = window.getInnerPanel();
Next, the following method must be called in the constructor before the GUI is instantiated in a frame.
void initializeKeys() {
// enable the inner panel to gain the focus of attention
inner.setFocusable(true);
// attach the pressed action object to the key adapter
keyadapter.addKeyPressedAction(keyAction);
}
Then, the following method must be called in the constructor after the GUI is instantiated in a frame.
void resetKeyFocus() {
// reset the focus of attention to the inner panel
// in case it has been set to some other component
inner.requestFocusInWindow();
}
The above method must also be called whenever the focus shifts to another component and the application wants the inner panel to again listen for key events. This is not needed in the demo program because the situation is so simple but in a more complicated program this method would need to be called at the end of any action that has shifted focus elsewhere.
In the code above, we mention the member data keyadapter and
keyAction. You can see these definitions in the file.
In summary, there is additional complexity in listening for keys since it is not obvious when a key is pressed who should pay attention and Java has to resolve this ambiguity by the concept of “focus”.
The file
KeyPlay.java
After the above file was posted, one student asked if it was possible to modify the program to handle pressing two cursor keys at once and thereby getting diagonal motion of the square. The program below accomplishes this goal.
The file
MultiKeyPlay.java
Added November 10, 2005: Unfortunately, MultiKeyPlay does not work in all cases so it is buggy. The bug is that if one key is pressed, then a second key, then the second key is released, Java fails to generate an automatic key event for the first key that is still pressed.
Creation of these programs was greatly assisted by looking at a demo program from the Sun Java Tutorial site. This program tracks each key press and release and then gives feedback into a scrolling text pane. The program enables you to see what Java is capable of knowing about key events.
The Sun Java Tutorial file
KeyEventDemo.java
This particular Sun Java Tutorial is at the site: How to Write a Key Listener
The code here is another attempt to solve the multiple-key-press problem. The code in KeyTrackerDemo1 is better but not entirely satisfactory since movement of the test paintable square is not quite smooth and there are other small but annoying glitches.
The file
StringInt.java
The above file is a simple data structure for a pair consisting of a
String and an int. Its application in this
code is to collect the name of a constant in a class and its value.
This is used with the Java classes
KeyEvent and InputEvent to explore what is
the constant int data these classes supply.
The file
StaticFields.java
The above file uses Java reflection to get lists of the
public static fields in a particular class
with a particular field type.
The case where the field type is int is handled
as a useful special case.
The file
BooleanStateArray.java
The above file defines a data structure that can match an
int from a specified list with a corresponding
boolean value that is viewed as its state. The
class is used to maintain the state of multiple key presses
in a GUI.
The file
Methods.java
The above file tests the data structure classes defined earlier.
The file
KeyPressReleaseListener.java
The above file creates a KeyListener that can
track the state of a given list of KeyEvent codes
or of all KeyEvent codes if you wish this level of
generality. This class utilizes BooleanStateArray.
The file
KeyTrackerTest.java
The above file tests that multiple key presses can be tracked but does no other work. For this demo, the keys tracked are the 4 arrow keys and the shift key.
The file
KeyTrackerDemo1.java
The above file tests that multiple key presses can be tracked and also
moves a paintable square as in the KeyPlay example posted
on November 2, 2005.
For this demo, the keys tracked are the 4 arrow keys and the shift key.
This demo sort of works but has some annoying glitches.
If these glitches can be resolved then there will be future postings on
this topic.
The code posted here now provides a reasonably satisfactory solution to the problem of tracking multiple key presses. Two files are new. First let us post a screen snapshot.
The file
KeyTrackerDemo2.java
This version of the key tracker uses two separate threads in addition to the standard “GUI thread”.
The first thread examines the state of the five keys of interest (up arrow, down arrow, left arrow, right arrow, and shift) and echoes this state into a small paintable that is shaped as a large plus sign with 5 tiles. When the shift key is pressed, the center tile is highlighted. When an arrow key is pressed, the corresponding tile (N, S, W, E) is highlighted. This thread already existed in the first version of the key tracker demo and its purpose is the show whether or not a key press or release has been detected by the software.
The second thread moves the paintable square if at least one arrow key is pressed. The purpose of the second thread is to have a longer delay if the paintable is being moved so that the movement delay is not forced to be the same as the much smaller delay that is used to signal detection of a key press or release. This design keeps the square from moving too quickly.
The file
PaintableComponentLite.java
This class replaces the JPT PaintableComponent class with one
that simply repaints if the internal paintable changes rather than do the
much more agressive refresh that includes repacking the entire window. In
hindsight, this is probably how PaintableComponent should
behave by default so I plan to incorporate this change into JPT at
semester break. Therefore, this class should be viewed as temporary.
The four files below are identical to those in the previous posting and continue to be essential for the solution.
The file
StringInt.java
The file
StaticFields.java
The file
BooleanStateArray.java
The file
KeyPressReleaseListener.java
I should mention one remaining glitch that is truly puzzling. I test this code on a Toshiba laptop that is connected in my office to an external monitor with its own keyboard and mouse. If I press 3 or 4 arrow keys at once on the external keyboard then sometimes a key press is not detected. Using the laptop keyboard, this failure never happens. This seems to be a peculiar hardware problem involving the external keyboard and the USB ports through which the key data passes. Unfortunately, this shows that the detection of multiple key presses has a fragility that cannot entirely be overcome by software. Software cannot track state that is not delivered by the hardware.
The file
ExtendedTileBox.java
This class allows a tile to remember the row and column position that the tile
occupies in a tile array structure. This means that it is not necessary to
have code that searches for or recomputes this position. This functionality
should probably be built into the JPT Tile base class so this is
another change to JPT that should happen at semester break.
Therefore, this class should be viewed as temporary.
This demo program illustrates a timed animation that produces a succession of paintables that accumulate one on top of another in 6 stages:
The animation timing delay is 1000 milliseconds = 1 second and the animation runs in a separate thread from the main “GUI thread”. It is essential to run processes with delays in a separate thread in order that the GUI remains responsive to the user actions.
Although this animation accumulates paintables, it would be equally easy to replace one paintable with another at each state to give the appearance of simple movement or more sophisticated transformations. We used accumulation in the demo simply so that all six stages would be visible in the final screen snapshot.
The file
AnimateSample.java
The 5 files posted today are:
The file
ShapeTools.java
The file
Shapes.java
The file
Geometry.java
The file
Methods.java
The file
IntersectTest.java
The class ShapeTools contains static methods for computing the union, intersection, set difference, and symmetric set difference (exclusive or) of arbitrary shapes. There is also a static method to test if two shapes intersect. In addition, there are methods to deal with mutation, in particular, a method that returns the mutated outline of a Paintable object.
Unfortunately, although these methods are mathematically accurate, they are also computationally intensive. This means that they cannot be used interactively to test if one shape being dragged intersects another shape. For this reason, IntersectTest updates the array of signals that shows when shapes overlap only when mouse dragging is complete.
The class Shapes contains factory methods to draw regular shapes including regular polygons, wavygons, and stars. These shapes are useful in general but also play a specific role in the tests.
The class Geometry has a method that computes the intersection of two line segments by using linear equations. This method is used to compute the outline of a star shape in Shapes.
The class Methods is the main test class for the content classes.
The class IntersectTest shows a set of signals that display when any pair from among 7 shapes intersects. The last shape is the outline of a text string in a large font. Some of the small shapes will fit into the open regions of the text outline and this may be used to demonstrate that the intersection code is mathematically accurate. Indeed, if one of the small shapes is entirely within an open region of the text outline then no intersection will be signaled.
The class IntersectTest has a main method so it may be launched directly. It may also be launched by a button in Methods.
This application provides an interactive venue in which a person can enter numbers into a Sudoku puzzle, experiment, remove numbers if needed, and save/restore a puzzle to a file (.sudoku). To enter or remove a number in a cell, click on the cell, press a key from 1 to 9 to enter a number or the keys 0 or blank to remove a number.
The puzzle will also supply hints if requested or clear such hints if the user wants to go back to working unaided. A trivial algorithm is run to initialize the hints. One or more of 3 sophisticated algorithms may be run to prune the hints. These algorithms may be run alone or in combination and may be run once or repeatedly. Often, if the algorithms are run repeatedly then the puzzle will be solved. If the hints in a cell become blank then the puzzle definitely cannot be solved. However, it is not known (to me) whether the algorithms are sufficient to solve any solvable puzzle with a unique solution.
Here are some screen snapshots at 67%. To see a full size image, click on the snapshot.
Puzzle 1
Puzzle 1 Solved
Here are the classes for Sudoku version 1.
The file
SudokuModel.java
This class maintains the data structure with the numbers already filled into the Sudoku puzzle cells and the related data structure for the hints computed for the empty cells. The class is also the center for the algorithms that prune the hints to remove those hints that may logically be proved to be impossible in the current situation. There are currently 3 pruning algorithms installed that may be executed individually or in combination either for a single cycle or repeatedly. An initial trivial algorithm is always run automatically when any puzzle cell changes. Here is an outline of the algorithms.
Algorithm 0 (Trivial).
For each cell that has a number entered by the user, eliminate that number as a hint from all cells in the same rol, column, or 3x3 block. This algorithm is always run once automatically.
Algorithm 1 (Triplet)
Suppose you have a triplet of 3 rows or 3 columns that all pass through a row of blocks or a column of blocks. Then under certain circumstances, you can argue that some hints may be eliminated. For example, if a triplet of 3 rows passes through a row of blocks then one can reason as follows. If one can show that a certain number must occur in one row of one of the blocks then that number may be eliminated as a hint in the same row of the other two blocks.
Algorithm 2 (Hint Sets)
Consider the set of hints for a row, a column, or a block that correspond to cells that are still empty. Suppose there exists a hint set of size k such that there exist (k-1) other hint sets that are subsets of this hint set (a subset may be equal). Then, all k hints may be removed from any other hint set for the same row, column, or block.
Algorithm 3 (Uniqueness)
Suppose for some value d, d turns out to occur in a given row, or a given column, or a given block in just one cell. Then that cell must have value d even if there are currently other hint values for that cell. Therefore, we can remove all other hints from that cell and we can remove d from all other cells in the same row, or same column, or same block as the cell in question.
The file
SudokuHint.java
This class encapsulates a data structure for the hint for a single cell in the puzzle. A hint is effectively a set of numbers from the Sudoku values of 1 to 9. Internally, a hint is represented as a boolean array of size 10 where only the index values from 1 to 9 are used. Externally a hint is represented in two ways. The first way is via the boolean function getHint that returns true if a number d is a member of the hint set and false if d is not a member of the hint set. The second way is as a bit sequence that is returned in an int via the hashCode function. Thus the hashCode is performing double duty both as a set representation and as the usual hash code value. One can use either external representation to deal with the hint as a set.
The file
SudokuBlock.java
This class encapsulates the GUI for one Sudoku cell.
The file
SudokuTable.java
This class encapsulates the GUI for the 9-by-9 table of Sudoku cells.
The file
Sudoku.java
This class encapsulates the GUI for the 9-by-9 table of Sudoku cells together with the assorted controls. This is the main program.
The file
StringableFileIO.java
This class manages file IO for a Sudoku puzzle. It is quite general and will be inserted into Java Power Tools in the next release.
Gravity Simulation
The file
GravSim.java
This class instantiates the Gravity Simulation GUI and launches the animation directed by the Mover object.
The file
Controls.java
This class provides interactive controls for the gravity simulation. These controls are in a separate window.
The file
Mover.java
This class manages the animation and is the heart of the algorithmics.
The file
Ball.java
This class instantiates the ball object that is animated.
Pong Game
The file
Pong.java
This class instantiates the Pong GUI and launches the animation directed by the Mover object.
The file
Mover.java
This class manages the animation and is the heart of the algorithmics.
The file
Ball.java
This class instantiates the ball object that is animated.