Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
1 Interactive GUI-Based Simon Game in Scala Leveraging Java Swing Libraries 2 Contents Motivation..................................................................................................................................................... 3 About Scala ................................................................................................................................................... 3 FlashTone ...................................................................................................................................................... 4 State Machine Diagram................................................................................................................................. 5 Game Thread................................................................................................................................................. 6 About StdAudio ............................................................................................................................................. 7 Java Web Start Deployment ......................................................................................................................... 8 About Java Swing Layouts ............................................................................................................................. 9 Bibliography .................................................................................................................................................. 9 3 Motivation The game Simon, invented by Milton Bradley in 1978, is an interesting example of a deterministic finite automaton (DFA). The code for the original board was written in Assembly Language, but modern highlevel languages such as C++, Java, or C# can easily implement the logic. In this instance, the author has opted to utilize a higher-level superset of Java known as Scala. The object of the game is to mimic a sequence of tones and flashing lights played by the computer. With each level completed, the length of the sequence increases by one, with the object of the game being to reach the highest level possible. Besides the state machine, multithreaded Java audio and GUI repaintings are additional computer science concepts exercised. About Scala Scala is a superset of Java which contains elements of functional programming languages such as LISP or ML. The Scala source is compiled to Java Virtual Machine byte code, and Java classes can be used as-is. Functional programming aspects include: ability to pass anonymous functions as arguments (lambda calculus), type inference, and its considering statements to be expressions with values. One mystery of the Scala compiler, NSC, is its ability to find Java classes such as javax.swing.JFrame referenced in Scala source without the JRE runtime jar files being in the library directory of the Scala install. In addition, no Windows environment variable is configured to specify the JAVA install directory or library classpath. Another mystery of the compiler is that it is written in the Scala language. It is expected that the original compiler was written in Java or a lower-level language and that it was used to compile the later Scalabased compiler. Then, the class generated from this Scala compiler could be used to compile its successors. Scala provides a concept called traits, similar to interfaces to Java. It also provides a form of weak inheritance known as “mix-ins”. One such mix-in, the EvalLoop trait, may explain the above classpath conundrum, as there is no default execution code in the compiler main class, NSC. In fact, though, the main execution code is located not in the EvalLoop trait but in Driver, the superclass of Main. Scala includes the ability to define anonymous inner classes, and the syntax is nearly identical to that in Java. This is useful in Swing, for instance, to override a JPanel’s paint method without explicitly defining a new subclass of JPanel. Scala contains its own versions of Java primitive types (e.g. Scala Int for Java int) and their boxed objects (e.g. RichInt for Integer). It is unclear whether the Scala types are automatically translated to their Java counterparts. Interestingly, though, the postfix-increment operator (++) does not seem to be defined for the Scala Int type. One downside of Scala’s dynamic type inference is the inability to initialize an object to null and later reassign it to a new instance of a class. Another mystery is the use of Java generic collections in Scala. A method like Map<T,T>’s “put” takes parameters of undefined type T. If an explicit type is passed to “put” in Scala, a compile error occurs. It would seem that casting Map<TextAttribute,?> to Map<TextAttribute,Integer> using the “asInstanceOf” operator might work, and in fact no compile 4 errors occurred when such syntax was resorted to (although it seems awkward to be required to cast the return value of a method). FlashTone This function will take an integer representing a color as input. 1=red 2=green 3=blue 4=yellow 5 The flash involves repainting the sector in a lighter shade of the color, and the tone aspect of the function involves playing a sound in a background thread (at a different frequency for each color). The repainting was initially attempted by changing the color variable for each sector and invoking the repaint method (reverting the color and invoking repaint again after a one-second delay). However, as paint operations in Java Swing (and thus Scala) are asynchronous, the first paint did not occur until the flash method completed, rendering the color change meaningless. Interestingly, after the update to the gui to deactivate the Textview and button once the game is started, the flash redraw of the board causes a duplicate rendering of the textview, the button, and the board in the frame. This problem was ameliorated by calling the clearRect method of the java.awt.Graphics class in the paint override of JPanel. State Machine Diagram Play Level Register User Play Tones Get User Input Pre-Start Game Over 6 Game Thread In order to avoid tying up the user interface’s dispatch thread with the indefinite while loop of the game, a separate thread is allocated for the game play loop. User clicks on the board are handled in the dispatch thread, but are checked only when the game is in the “userInputPhase”. In the user input phase, the user will have up to ten seconds to press a key, and each color enered will be checked against the tones played for that level. This is basically a finite state machine architecture, with the user input state being broken down into sub-states for each tone/color to be checked. For now, if the incorrect key is pressed, the game simply ends and a tone is played. However, the “canonical” behavior would be to both play a tone and to flash the color of the correct key. Checking of a color pressed involves comparing the sector of the correct color to the sector of the location clicked (touched), based on the Cartesian coordinates of the click with the center of the circle as the origin. When the game ends, a “Play Again” button is enabled. When this is clicked, the game is returned to the state user name input (see screen shot below). Note that the game thread never terminates once it is started while the application is running. It is suspended when the game ends and resumed when the game is restarted (with a reset of instance variables like level number and tones string). Note that “wait” and “notify” operations could have been used in place of the deprecated “suspend” and “resume” operations, but it would have been necessary to place these operations within synchronized blocks in order to obtain the monitor lock on the object. Note that the process to respond to errors or level completion has been streamlined by interrupting the ten-second sleep in the game thread’s “get input” loop whenever either an incorrect sector click is detected or a level completion is verified. The “interrupt” method of java.lang.Thread is called from the GUI dispatch thread and is applied to the thread represented by the “this” object reference, namely the game thread. 7 About StdAudio This library, developed by Robert Sedgewick and Kevin Wayne of Princeton University’s Computer Science department (used without permission), enables sounds to be played from Java by providing only a frequency and sample rate. Its play method takes a double and uses this double to write a distinct byte stream to the speaker’s shared memory (accessed in Java using a Line object). Apparently, the SourceDataLine class in object writes to the output speaker/headphone port (via the mixer) by default. 8 The primary function of this library is “play”. To use it to play a tone for one second, iterate over a for loop with index i “sample rate” times. In each iteration, pass .5sin(2pi*i*f/sampleRate) to play. Thus, over the “for” loop, values in [-.5, .5] are passed, with the argument to the sin function increasing by 2pi*f/sampleRate with each iteration. Unfortunately, the StdAudio methods are not threadsafe, so the play calls must be made within a synchronized block (use this.synchronized). In fact, as the bufferSize variable is static, the entire for loop calling play and the succeeding close (releases the speaker resource) call should be in a synchronized block. This locking needs to be conducted at the class level, so the “playRange” method of SoundThread is defined at the “object” level, making it static. The “synchronized” keyword thus provides mutually exclusive access to the class (across all instances) for a given thread. Note that one problem in playing tones was excessively calling the “close” method excessively. This results in a drain and closure of the “line” audio resource (shared memory for sound card). As the method is static, it can be called only once (at the end of the game). Excessive static occurred when the game was first started and when the Simon application was in focus, but the problem has not recurred. This may have been due to memory usage on the test machine. An alternative to the above procedure would have been to record tones in four .wav files and to play these in a background thread when tones are to be souned. Java Web Start Deployment This step, which essentially involves packaging the Java GUI code in an archive which can be downloaded from a web site and executed on a client PC is actually non-trivial. Steps involved include: 1. Creating a Java Archive (JAR) file including the Scala classes needed. This involves extracting the Scala classes from their JAR files and adding them into the new deployment JAR at the appropriate path. 2. Signing the JAR file using a private key and appending public key to it. 3. Creating a Java Network Launch Protocol (JNLP) file describing the JAR and any command-line options needed to run it. 4. Modifying an HTML site to link to the JNLP file. The following commands were used to package the deployment JAR (after extracting scala-library.jar to the current directory). jar -cvfm simonem.jar manifest.txt *.class jar -uvf simonem.jar *.png jar -uvf simonem.jar scala The manifest.txt file must contain: Permissions: sandbox The JNLP file will induce the start of a download module on the client PC, and a Java Virtual Machine (JVM) will subsequently be launched. 9 Two other items of consequence in the deployment are the Java Control Panel Security (must be at Medium to allow a self-signed certificate) and the manifest (specifies run permissions for the downloaded classes). About Java Swing Layouts Placing GUI widgets in a frame or panel using Cartesian pixel coordinates produced unpredictable results, so the author has resorted to utilizing a GridBagLayout to organize the GUI controls and displays. Interestingly, the “gridwidth”, “gridheight”, “gridx”, and “gridy” traits seem ineffective at organizing the layout precisely. Instead, the “fill”, “weighty”, and “weightx” traits, along with the “setSize” value of the component to be added, seemed to determine the position and size of the widgets. However, the “gridx” and “gridy” values are necessary to determine the row and column values in the layout. An unexplained bug with the repainting of the circle has been noticed at random level changes. In such a case, a portion of the green sector is painted above the circle to the left of the “start” button. It is unclear whether the source of this behavior lies in Scala library code, Java Swing code, or the Simon Emulator application source. It seems unlikely that the operating system is the cause of the problem, as other applications do not exhibit the same repainting problem. In fact, the problem seems to be with the application code which calls repaint of the board both from a background thread (during playGame) and from the dispatch thread when a mouse click on the board occurs. When the paint occurs from a background thread the paint method invocation must be wrapped in a SwingUtilities.invokeAndWait call. When called from the dispatcher thread, the paintImmediately method should be used. Also, the rectangular area for the repaint did not completely overlap with the actual rectangle. Upon correcting these issues, the aberrant paint problems seem to have been corrected. Bibliography http://www.tutorialspoint.com/scala/scala_for_loop.htm Scala for loop syntax http://www.scala-lang.org/ Scala home page http://en.wikipedia.org/wiki/Scala_(programming_language) Wikipedia Scala discussion http://docs.oracle.com/javase/6/docs/api/java/awt/Graphics.html Graphics class (contains fillArc) http://introcs.cs.princeton.edu/java/stdlib/StdAudio.java.html audio library used to play tones http://en.wikipedia.org/wiki/Simon_(game) Simon discussion. http://docs.oracle.com/javase/tutorial/deployment/webstart/deploying.html Java Web Start deployment steps