Trouble decoding morse code using HashMaps.

767 views Asked by At

My code works fine on encoding regular text to Morse code, but when i attempt to translate the other way, I am hit with an index out of bounds error. No idea why?

import java.util.HashMap;
public class MorseCode {
private final String alphabet = "abcdefghijklmnopqrstuvwxyz0123456789 ";
private final String[] morse = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---",
        ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", ".----", "..---", "...--", "....-", ".....",
        "-....", "--...", "---..", "----.", "-----", "|"};
private HashMap<String, String> toText;
private HashMap<String, String> toCode;

public MorseCode() {
    toText = new HashMap<>();
    toCode = new HashMap<>();
    char[] alphaArray = alphabet.toCharArray();
    for(int i = 0; i < morse.length; i++) {
        toCode.put(morse[i], String.valueOf(alphaArray[i]));
        toText.put(String.valueOf(alphaArray[i]), morse[i]);
    }

}

public String encode(String s) {
    s = s.toLowerCase();
    String encoded = "";
    char[] chars = s.toCharArray();
    for(int i = 0; i < s.length(); i++) {
        for (HashMap.Entry<String, String> entry : toCode.entrySet()) {
            if (String.valueOf(chars[i]).equals(entry.getValue())) {
                encoded += entry.getKey() + " ";
            }
        }
    }

    return encoded;
}

public String decode(String s) {
    s = s.toLowerCase();
    String decoded = "";
    for(int i = 0; i < s.length(); i++) {
        for (HashMap.Entry<String, String> entry : toText.entrySet()) {
            if (morse[i].equals(entry.getValue())) {
                decoded += entry.getKey();
            }
        }
    }

    return decoded;
}

}

Trying to find a solution that works both ways, any help/advice would be appreciated!

1

There are 1 answers

0
rafaelbattesti On BEST ANSWER

I tested this code and it is working. Be aware that this is a very rudimentary implementation, but properly using some of the conveniences of the HashMap class. I strongly advise you running in debug mode and tracing the values of the variables.

import java.util.HashMap;

public class MorseCode {

    //Constants hold the accepted characters
    private final String alphabet = "abcdefghijklmnopqrstuvwxyz0123456789 ";
    private final String[] morse = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---",
        ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", ".----", "..---", "...--", "....-", ".....",
        "-....", "--...", "---..", "----.", "-----", "|"};

    //Maps map the code to text and text to code
    private HashMap<String, String> toText;
    private HashMap<String, String> toCode;

    //Problem: toText had text as keys. Keys should be used to identify the value your want to get.
    //Solution: swapped toText logic to toCode logic
    public MorseCode() {
        toText = new HashMap<>();
        toCode = new HashMap<>();
        char[] alphaArray = alphabet.toCharArray();
        for(int i = 0; i < morse.length; i++) {
            toText.put(morse[i], String.valueOf(alphaArray[i]));
            toCode.put(String.valueOf(alphaArray[i]), morse[i]);
        }
    }

    //Problem: kind of complicated logic. Was working, but did not need all that truncation
    //Solution: HashMap contains neat methods to work with keys - get(key) and containsKey(key)
    //In this solution, if the key is not found, we print the plain text character
    public String encode(String s) {
        s = s.toLowerCase();
        String encoded = "";
        for(int i = 0; i < s.length(); i++) {
            String c = String.valueOf(s.charAt(i));
            if (toCode.containsKey(c)) {
                encoded += toCode.get(c) + " ";
            } else {
                encoded += c;
            }
        }
        return encoded;
    }

    //Problem: logic was broken. Again, you are mapping the key to the value you want in toText, so use it.
    //Solution: Same logic than the encode method, but we had to strip off the spaces
    public String decode(String s) {
        String[] code = s.split(" ");
        String decoded = "";
        for(int i = 0; i < code.length; i++) {
            if (toText.containsKey(code[i])) {
                decoded += toText.get(code[i]);
            } else {
                decoded += "?";
            }
        }
        return decoded;
    }
}

Test code in the main method. This test should really take all boundary cases (special characters, multiple spaces, empty strings, etc) and compare the input with the expected output. But it's too late for that. :-)

public class Main {
    public static void main(String[] args) {
        MorseCode m = new MorseCode();
        String encoded = m.encode("Unencoded Text");
        String decoded = m.decode("..- -. . -. -.-. --- -.. . -.. | - . -..- - ");
        System.out.println(encoded);
        System.out.println(decoded);

    }
}

Cheers.