4

I'm trying to write a while switch case kinda code for modeling a finite state machine that searches a string of As and Bs to see if the string "ABBA" is present. When I input just "ABBA", it outputs Word found! like it's supposed to. However, if I input "AABBA" it doesn't find the word & output the right message. Any help is appreciated. Thanks!

import java.util.*;
public class AB{
    public static void main(String args[]){
        Scanner input = new Scanner(System.in);
        String word = input.next();
        int current = 0;
        int status = 0;
        System.out.println("Starting to evaluate...");
        while(status != 4){
            for(int i = current; i < word.length(); i++){
                String part = word.substring(current, i + 1);
                switch(status){
                    case 0: //start
                        if(part.equals("A")){
                            status = 1;
                        }
                        else if(part.equals("B"){
                            status = 0; 
                            current = i;
                        }
                    break;
                    case 1: //A is there now
                        if(part.equals("AB")){
                            status = 2;
                        }
                        else if(part.equals("AA"){
                            status = 1;
                            current = 1;
                        }
                    break;
                    case 2: //AB is there now
                        if(part.equals("ABB")){
                            status = 3;
                        }
                        else if(part.equals("ABA"){
                            status = 1;
                            current = 1;
                        }
                    break;
                    case 3: //ABB is there now
                        if(part.equals("ABBA")){
                            status = 4;
                            System.out.println("Word found!");
                        }
                        else if(part.equals("ABBB"){
                            status = 0;
                            current = i;
                        }
                    break;
                }
            }
        }
    }
}
Anna
  • 379
  • 5
  • 16
  • while/switch construction is a requirement? – Alexey R. Jul 28 '17 at 16:33
  • @AlexeyR. yeah it is – Anna Jul 28 '17 at 16:34
  • I changed String word = input.next() to String word = "AABBA" and it worked fine. Are you sure it's not a scanner issue. – Malphrush Jul 28 '17 at 16:38
  • 3
    A side note - in a state machine, it makes more sense to compare only the "next" letter in every step. The previous letters were already tested in the previous steps, and they got you to the current *state* (`status x`), so no need to compare the whole string again, just the additional character. – SHG Jul 28 '17 at 16:42
  • it actually finds `AABBA`. Mind that if the first word you provide doesn't contain `ABBA`, your program will be stuck forever in the `while` loop – nandsito Jul 28 '17 at 16:43
  • @Malphrush I changed it to String word = "AABBA" but it's not working for me . @nandsito it finds it AABBA with the scanner? That doesn't work for me actually. My program doesn't ask the user repeatedly for a string of A's and B's to search. Do you mean that if the string doesn't contain ABBA it'll run an infinite loop then? I suppose the solution would be to have the condition `current != word.length` in the while loop, right? – Anna Jul 28 '17 at 16:52
  • so while(status != 4 && current != word.length) would make sure it doesn't run an infinite loop? – Anna Jul 28 '17 at 16:53
  • @SHG I see what you mean, that is way more efficient. So instead I'd have `String part = word.substring(i, i+1);` to evaluate each character as I go.. – Anna Jul 28 '17 at 16:57
  • Using regex to explain me: what is exactly the pattern that you want to match: `A+BBA+` or `ABBA`? If you define the pattern with regular expression you could get a DFA or NFA wich help you how to designe your code. – Jorge Omar Medra Jul 30 '17 at 06:37

2 Answers2

3

What I can see ineffective in your approache is that you actually do not use the power of a state machine. First of all you should understand what drives your machine through the states. In your example each sequential letter of the input string does. Since you have taken a state you should now check to which state would the next symbol switch your machine. Let me suggest the following implementation..

Here is the state diagram:

enter image description here

Here is the code implementing the diagram:

public boolean abbaMatcher(String abba)
{
    int state = 0;
    int symbol = 0;


    while (symbol < abba.length()){
        char c = abba.charAt(symbol);
        switch (state){
            case 0: if(c == 'a'){
                        state = 1;
                    }else{
                        state = 0;
                    };
                    break;
            case 1: if(c == 'b'){
                        state = 2;
                    }else{
                        state = 1;
                    };
                    break;
            case 2: if(c == 'b'){
                        state = 3;
                    }else{
                        state = 1;
                    };
                    break;
            case 3: if(c == 'a'){
                        return true;
                    }else{
                        state = 0;
                    };
                    break;
        }
        symbol++;
    }

    return false;
}

This could be written more easily with just a for loop, however the while/switch construnction is a requirement.

Alexey R.
  • 8,057
  • 2
  • 11
  • 27
  • 2
    You should address what you changed about the OPs code and why your's works better. You should also address the problems in their code. Merely saying, "use this code instead" is not helpful. – Malphrush Jul 28 '17 at 16:51
  • 1
    You just did someone's homework for them. On questions that are clearly abstract and homework-like it's often a good idea to consider questions that will lead them to repair their solutions rather than dropping an answer in their lap. Not downvoting or anything, just a suggestion. – Bill K Jul 28 '17 at 16:52
  • 2
    I like it, but it wold be better if you add the transition diagram to understand at all your implementation. – Jorge Omar Medra Jul 28 '17 at 16:53
  • @JorgeOmarMedra I wanted to add one however I'm not sure there is a reliable way to paste a picture here so that it preserves "for ages" – Alexey R. Jul 28 '17 at 16:55
  • @AlexeyR. Yes, there is an option into the bar tool to add a picture where you can drag and drop it. It is between `Code Saplme` and `JavaScript/HTML/CSS Snipped`. – Jorge Omar Medra Jul 28 '17 at 16:59
0

The following code is similar to your implementation but it accounts for dynamic sequences (different sequences), and does not mess with substrings but rather iterates over the string's underlying character array.

It also accounts for a sequence that starts in another sequence, for instance: Looking for the sequence "ABAB" in the string "ABABAB" would have the results "ABAB" found at index 0 and "ABAB" found at index 2. This can easily be removed by commenting out wIndex = startIndex.

Code:

public static void main (String[] args) throws java.lang.Exception {
    // Scanner input = new Scanner(System.in);
    String word = "B BABBABBA B";
    String seq = "ABBA";
    char[] wChars = word.toCharArray();
    char[] sChars = seq.toCharArray();
    int wIndex = 0; // wChars index
    int sIndex = 0; // sChars index
    int startIndex = 0; // starting index of the seq found in wChars

    System.out.println("Starting to evaluate...");

    while(wIndex < wChars.length) {
        if(wChars[wIndex] == sChars[sIndex]) {
            if(sIndex == 0) {
                startIndex = wIndex;
            }
            sIndex += 1;
        } else {
            sIndex = 0;
        }

        if(sIndex >= sChars.length) {
            System.out.println("Sequence \"" + seq + "\" found at index " + startIndex + ".");
            sIndex = 0;
            wIndex = startIndex; // set wIndex to startIndex to account for
                                 // sequence within a sequence, basically
                                 // backtracking
        }

        wIndex += 1;
    }
}

Output:

Starting to evaluate...
Sequence "ABBA" found at index 3.
Sequence "ABBA" found at index 6.
Jonny Henly
  • 4,023
  • 4
  • 26
  • 43