Skip to content

Commit 19ff2eb

Browse files
amihaiemilpivovarit
authored andcommitted
finite automata example (eugenp#1364)
1 parent 818eeee commit 19ff2eb

7 files changed

Lines changed: 254 additions & 0 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.baeldung.automata;
2+
3+
/**
4+
* Finite state machine.
5+
*/
6+
public interface FiniteStateMachine {
7+
8+
/**
9+
* Follow a transition, switch the state of the machine.
10+
* @param c Char.
11+
* @return A new finite state machine with the new state.
12+
*/
13+
FiniteStateMachine switchState(final CharSequence c);
14+
15+
/**
16+
* Is the current state a final one?
17+
* @return true or false.
18+
*/
19+
boolean canStop();
20+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.baeldung.automata;
2+
3+
/**
4+
* Default implementation of a finite state machine.
5+
* This class is immutable and thread-safe.
6+
*/
7+
public final class RtFiniteStateMachine implements FiniteStateMachine {
8+
9+
/**
10+
* Current state.
11+
*/
12+
private State current;
13+
14+
/**
15+
* Ctor.
16+
* @param initial Initial state of this machine.
17+
*/
18+
public RtFiniteStateMachine(final State initial) {
19+
this.current = initial;
20+
}
21+
22+
public FiniteStateMachine switchState(final CharSequence c) {
23+
return new RtFiniteStateMachine(this.current.transit(c));
24+
}
25+
26+
public boolean canStop() {
27+
return this.current.isFinal();
28+
}
29+
30+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.baeldung.automata;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* State in a finite state machine.
8+
*/
9+
public final class RtState implements State {
10+
11+
private List<Transition> transitions;
12+
private boolean isFinal;
13+
14+
public RtState() {
15+
this(false);
16+
}
17+
18+
public RtState(final boolean isFinal) {
19+
this.transitions = new ArrayList<>();
20+
this.isFinal = isFinal;
21+
}
22+
23+
public State transit(final CharSequence c) {
24+
for(final Transition t : this.transitions) {
25+
if(t.isPossible(c)) {
26+
return t.state();
27+
}
28+
}
29+
throw new IllegalArgumentException("Input not accepted: " + c);
30+
}
31+
32+
public boolean isFinal() {
33+
return this.isFinal;
34+
}
35+
36+
@Override
37+
public State with(Transition tr) {
38+
this.transitions.add(tr);
39+
return this;
40+
}
41+
42+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.baeldung.automata;
2+
3+
4+
/**
5+
* Transition in finite state machine.
6+
*/
7+
public final class RtTransition implements Transition {
8+
9+
private String rule;
10+
private State next;
11+
12+
/**
13+
* Ctor.
14+
* @param rule Rule that a character has to meet
15+
* in order to get to the next state.
16+
* @param next Next state.
17+
*/
18+
public RtTransition (String rule, State next) {
19+
this.rule = rule;
20+
this.next = next;
21+
}
22+
23+
public State state() {
24+
return this.next;
25+
}
26+
27+
public boolean isPossible(CharSequence c) {
28+
return this.rule.equalsIgnoreCase(String.valueOf(c));
29+
}
30+
31+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.baeldung.automata;
2+
3+
/**
4+
* State. Part of a finite state machine.
5+
*/
6+
public interface State {
7+
8+
/**
9+
* Add a Transition to this state.
10+
* @param tr Given transition.
11+
* @return Modified State.
12+
*/
13+
State with(final Transition tr);
14+
15+
/**
16+
* Follow one of the transitions, to get
17+
* to the next state.
18+
* @param c Character.
19+
* @return State.
20+
* @throws IllegalStateException if the char is not accepted.
21+
*/
22+
State transit(final CharSequence c);
23+
24+
/**
25+
* Can the automaton stop on this state?
26+
* @return true or false
27+
*/
28+
boolean isFinal();
29+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.baeldung.automata;
2+
3+
/**
4+
* Transition in a finite State machine.
5+
*/
6+
public interface Transition {
7+
8+
/**
9+
* Is the transition possible with the given character?
10+
* @param c char.
11+
* @return true or false.
12+
*/
13+
boolean isPossible(final CharSequence c);
14+
15+
/**
16+
* The state to which this transition leads.
17+
* @return State.
18+
*/
19+
State state();
20+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package algorithms;
2+
3+
import static org.junit.Assert.*;
4+
import org.junit.Test;
5+
import com.baeldung.automata.*;
6+
7+
/**
8+
* Tests for {@link RtFiniteStateMachine}
9+
*/
10+
public final class RtFiniteStateMachineTest {
11+
12+
@Test
13+
public void acceptsSimplePair() {
14+
String json = "{\"key\":\"value\"}";
15+
FiniteStateMachine machine = this.buildJsonStateMachine();
16+
for (int i=0;i<json.length();i++) {
17+
machine = machine.switchState(String.valueOf(json.charAt(i)));
18+
}
19+
assertTrue(machine.canStop());
20+
}
21+
@Test
22+
public void acceptsMorePairs() {
23+
String json = "{\"key1\":\"value1\",\"key2\":\"value2\"}";
24+
FiniteStateMachine machine = this.buildJsonStateMachine();
25+
for (int i=0;i<json.length();i++) {
26+
machine = machine.switchState(String.valueOf(json.charAt(i)));
27+
}
28+
assertTrue(machine.canStop());
29+
}
30+
31+
@Test(expected = IllegalArgumentException.class)
32+
public void missingColon() {
33+
String json = "{\"key\"\"value\"}";
34+
FiniteStateMachine machine = this.buildJsonStateMachine();
35+
for (int i=0;i<json.length();i++) {
36+
machine = machine.switchState(String.valueOf(json.charAt(i)));
37+
}
38+
}
39+
40+
/**
41+
* Builds a finite state machine to validate a simple
42+
* Json object.
43+
* @return
44+
*/
45+
private FiniteStateMachine buildJsonStateMachine() {
46+
State first = new RtState();
47+
State second = new RtState();
48+
State third = new RtState();
49+
State fourth = new RtState();
50+
State fifth = new RtState();
51+
State sixth = new RtState();
52+
State seventh = new RtState();
53+
State eighth = new RtState(true);
54+
55+
first.with(new RtTransition("{", second));
56+
second.with(new RtTransition("\"", third));
57+
//Add transitions with chars 0-9 and a-z
58+
for (int i = 0; i < 26; i++) {
59+
if(i<10) {
60+
third = third.with(
61+
new RtTransition(String.valueOf(i), third)
62+
);
63+
sixth = sixth.with(
64+
new RtTransition(String.valueOf(i), sixth)
65+
);
66+
}
67+
third = third.with(
68+
new RtTransition(String.valueOf((char) ('a' + i)), third)
69+
);
70+
sixth = sixth.with(
71+
new RtTransition(String.valueOf((char) ('a' + i)), sixth)
72+
);
73+
}
74+
third.with(new RtTransition("\"", fourth));
75+
fourth.with(new RtTransition(":", fifth));
76+
fifth.with(new RtTransition("\"", sixth));
77+
sixth.with(new RtTransition("\"", seventh));
78+
seventh.with(new RtTransition(",", second));
79+
seventh.with(new RtTransition("}", eighth));
80+
return new RtFiniteStateMachine(first);
81+
}
82+
}

0 commit comments

Comments
 (0)