Lab 11: Morse Code Encoder
Learning Outcomes
- Have a thorough understanding of commonly used library data structures
- Use data structures in software design and implementation
- Describe how elements are added to a hash table
- Describe the chaining method for dealing with collisions within a hash table
- Write a hash table implementation using chaining
- Use a hash table to implement a
Map - Apply the
Map<K, V>interface defined in the Java Collections Framework
Overview
In this lab, you will implement a program that encodes text messages into Morse code. You will use a map that you implement yourself to look up the Morse code associated with each character.
Your program's GUI will be similar to the one from Lab 9, with menu items used to select actions. The interface should match the supplied example as closely as reasonably possible. Minor platform-specific differences in fonts, spacing, and native control appearance are acceptable.
Sample Results
Running your program on this file:
A space should be placed between each encoded character. A **'' ''** should be placed between each word. Line breaks in the input file should be replicated in the encoded file.
should display the following in an Alert after encoding:
Warning: skipping: * Warning: skipping: * Warning: skipping: ' Warning: skipping: ' Warning: skipping: ' Warning: skipping: ' Warning: skipping: * Warning: skipping: *
and produce the following output:
.- .-... ... .--. .- -.-. . .-... ... .... --- ..- .-.. -.. .-... -... . .-... .--. .-.. .- -.-. . -.. .-... -... . - .-- . . -. .-... . .- -.-. .... .-... . -. -.-. --- -.. . -.. .-... -.-. .... .- .-. .- -.-. - . .-. .-.-.- .-.- .-.- .- .-... .-... .-... ... .... --- ..- .-.. -.. .-... -... . .-... .--. .-.. .- -.-. . -.. .-... -... . - .-- . . -. .-... . .- -.-. .... .-... .-- --- .-. -.. .-.-.- .-.- .-.- .-.. .. -. . .-... -... .-. . .- -.- ... .-... .. -. .-... - .... . .-... .. -. .--. ..- - .-... ..-. .. .-.. . .-... ... .... --- ..- .-.. -.. .-... -... . .-... .-. . .--. .-.. .. -.-. .- - . -.. .-... .. -. .-... - .... . .-... . -. -.-. --- -.. . -.. .-... ..-. .. .-.. . .-.-.- .-.-
Implementation
In addition to the MorseEncoderDriver class that launches the GUI, you will
write and test three classes: MorseEncoder, HashMap, and Controller.
MorseEncoderDriver
Create a MorseEncoderDriver class that extends Application.
It must:
- provide a
public static void main(String[] args)method that launches the application; - override
public void start(Stage stage); - load
morseEncoder.fxml; - obtain the
Controllerfrom theFXMLLoaderand provide it with the applicationStage; - create and display the scene;
- use
Morse Encoderas the application title.
MorseEncoder
MorseEncoder is a utility class that loads the Morse Code table, encodes
messages, and provides the tone-playing method used by the GUI.
The class must contain a private static map named MAP:
private static final HashMap<Character, String> MAP = new HashMap<>();
MorseEncoder must contain the following methods:
-
public static void loadTable(Path path) throws IOException— accepts aPathto a Morse Code table file and populatesMAPwith the codes and their corresponding symbols. The method must clear any previous contents fromMAPbefore loading the new table. It should use theput()method from yourHashMapimplementation to populate the table.Normal dictionary entries begin with the character being encoded, followed immediately by the Morse code. The newline character is represented by the two characters
\n, so its Morse code begins after those two characters. -
public static List<String> encodeMessage(String message)— accepts a text message and returns a list containing the encoded message and any warnings that were generated.The returned list must use the following structure:
index 0 encoded message index 1+ warning messages, one for each skipped characterCharacters must be converted to uppercase before lookup, so lowercase input is encoded using the uppercase mappings in the table.
A single space must separate encoded character tokens. If the source message contains a newline, encode the newline using its Morse code and then insert an actual line break in the encoded output.
If a character is not present in
MAP, do not encode it. Instead, add one warning to the returned list for that character and continue encoding the rest of the message. -
public static void playTone(boolean dot)— this method is provided to assist in playing an encoded message. Ifdotistrue, it plays a short dot sound. Ifdotisfalse, it plays a dash sound that is three times the length of the dot sound.
HashMap
Your HashMap<K, V> class must implement the
Map<K, V> interface.
This implementation uses chaining to handle collisions. The backing table
must be an array named entries with a length of 1024. Each array location is
either null or refers to a list of Map.Entry<K, V> objects. Keys that hash
to the same array index are stored in the same list.
The class must define a private nested HashMapEntry<K, V> class that
implements Map.Entry<K, V>.
Use the key's hashCode() to determine the array index. Negative hash codes
must still result in valid non-negative array indexes.
Keys may not be duplicated. Calling put() with a key that is already present
must replace the value associated with that key without changing the size of
the map.
This implementation does not need to resize the backing array or track collision statistics.
null keys are not supported. null values are permitted.
Your implementation must provide working implementations of the following
Map methods. The remaining Map methods may throw an
UnsupportedOperationException.
clear()containsKey(Object key)containsValue(Object value)get(Object key)isEmpty()put(K key, V value)remove(Object key)size()
Follow the Map contract for return values. In particular:
put()returns the previous value associated with the key, ornullif there was no previous mapping;remove()returns the value that was associated with the removed key, ornullif the key was not present;get()returns the value associated with the key, ornullif the key is not present.
Controller
Your Controller class must implement the Initializable interface and provide
at minimum the following functionality:
-
public void initialize(URL url, ResourceBundle resourceBundle)— loads the Morse Code table fromdata/morseCode.txtonce the GUI has been loaded. -
void open()— asks the user for the text file to encode, displays the exact contents of the file in the input area, encodes the message, and displays the encoded message in the output area. -
void save()— asks the user for a filename and saves the encoded message. -
void quit()— exits the program. -
void clear()— clears the input and output text from the GUI and disablesSaveandPlay. -
void about()— displays an informationalAlertwith instructions for using the program. -
void play()— plays the encoded message usingMorseEncoder.playTone().
If any characters cannot be encoded, the Controller must skip them, continue
encoding the remaining message, and display one Alert after encoding is
complete containing all warning messages returned by encodeMessage().
GUI Requirements
The GUI must be defined in morseEncoder.fxml.
The interface should contain two large, non-editable text areas:
- the upper area displays the original text;
- the lower area displays the encoded Morse message.
There must be three menus: File, Edit, and Help.
File contains:
OpenSavePlayQuit
Edit contains:
Clear
Help contains:
About
Save and Play must be disabled whenever there is no encoded message
displayed, including when the application first starts and after Clear is
selected.
Each menu item must be usable with either the mouse or the platform shortcut key (Command on macOS, Ctrl on Windows/Linux):
- Shortcut-O: Open
- Shortcut-S: Save
- Shortcut-P: Play
- Shortcut-Q: Quit
- Shortcut-Delete: Clear
- Shortcut-H: About
The contents of an opened text file must be preserved exactly. Do not add or remove line breaks while reading the source file.
Morse Playback
When playing the encoded message, use Thread.sleep(int milliseconds) to
produce silence between encoded characters and between lines.
Use the following timing:
- Dot: 50 ms
- Dash: 150 ms
- Time between encoded characters: 150 ms
- Time between lines: 450 ms
Spaces and newline characters have their own Morse codes and must be played as normal encoded tokens. In addition, pause between encoded characters and after each encoded line as described above.
Acknowledgements
This assignment was developed by Dr. Jay Urbain, Dr. Chris Taylor, Dr. RJ Nowling, and Prof. Sean Jones.