Finite state machine: Difference between revisions
Include the state in the prompt
m (→{{header|J}}) |
(Include the state in the prompt) |
||
(8 intermediate revisions by 6 users not shown) | |||
Line 36:
{{trans|Python}}
<
(‘Machine ready: (d)eposit, or (q)uit?’,
[String(‘d’), ‘q’]),
Line 80:
current_state = :states[next_state]
finite_state_machine(‘ready’, ‘q’)</
{{out}}
Line 91:
Refunding money
Machine ready: (d)eposit, or (q)uit?q
</pre>
=={{header|ALGOL 68}}==
<syntaxhighlight lang="algol68">
BEGIN # finite state machine #
# mode representing a state in the FSM #
MODE FSMSTATE = STRUCT( INT state # code for the state #
, PROC INT next state # routine to change state #
);
# executes the FSM defined by states, starting from the initial state #
# and terminating when the exit state is reached #
PROC run fsm = ( []FSMSTATE states, INT initial state, exit state )VOID:
BEGIN
INT state := initial state;
WHILE state /= exit state DO
BOOL found := FALSE;
FOR s pos FROM LWB states TO UPB states WHILE NOT found DO
IF found := state OF states[ s pos ] = state THEN
state := next state OF states[ s pos ]
FI
OD;
IF NOT found THEN
# in an invalid state - restart #
print( ( "(resetting)", newline ) );
state := initial state
FI
OD
END # run fsm # ;
BEGIN # test FSM #
# possible states #
INT exit = 0, ready = 1, waiting = 2, dispense = 3, refunding = 4;
# prompts the user for a single character code and returns it #
# the user is re-prompted until they enter one of the characters in #
# answers #
PROC get code = ( STRING prompt, answers )CHAR:
BEGIN
CHAR response;
WHILE print( ( prompt, ": " ) );
STRING answer;
read( ( answer, newline ) );
response := IF answer = "" THEN REPR 0 ELSE answer[ LWB answer ] FI;
IF response >= "a" AND response <= "z" THEN
# convert lowercase response to upper #
response := REPR ( ABS response + ( ABS "A" - ABS "a" ) )
FI;
NOT char in string( response, NIL, answers )
DO SKIP OD;
response
END # get code # ;
run fsm( ( ( ready
, INT: IF "Q" = get code( "Ready : Enter D to deposit, Q to Quit", "DQ" )
THEN exit
ELSE waiting
FI
)
, ( waiting
, INT: IF "S" = get code( "Waiting : Enter S to Select, R to Refund", "SR" )
THEN dispense
ELSE refunding
FI
)
, ( dispense
, INT: BEGIN get code( "Dispensing: Remove your product and Enter R", "R" );
ready
END
)
, ( refunding
, INT: BEGIN print( ( "Refunding", newline ) ); ready END
)
)
, ready
, exit
)
END
END
</syntaxhighlight>
{{out}}
<pre>
Ready : Enter D to deposit, Q to Quit: d
Waiting : Enter S to Select, R to Refund: s
Dispensing: Remove your product and Enter R: r
Ready : Enter D to deposit, Q to Quit: d
Waiting : Enter S to Select, R to Refund: r
Refunding
Ready : Enter D to deposit, Q to Quit: q
</pre>
=={{header|BASIC}}==
==={{header|Commodore BASIC}}===
<
10 REM FINITE STATE MACHINE
20 LET MS=1: REM MACHINE STATE
Line 141 ⟶ 232:
5010 PRINT "MACHINE IS SHUTDOWN"
5020 END
</syntaxhighlight>
==={{header|Sinclair ZX81 BASIC}}===
Works with 1k of RAM.
Line 153 ⟶ 244:
Note that the program uses no variables and makes no use of the return stack: all the state is expressed in the (so to speak) state.
<
20 IF INKEY$="D" THEN GOTO 50
30 IF INKEY$="Q" THEN STOP
Line 167 ⟶ 258:
130 GOTO 120
140 PRINT "REFUNDED"
150 GOTO 10</
{{out}}
It will be seen that the user has pressed, in order, <tt>D</tt>, <tt>R</tt>, <tt>D</tt>, <tt>S</tt>, <tt>R</tt>, and <tt>Q</tt>.
Line 181 ⟶ 272:
=={{header|C}}==
Here is a manually-constructed table-driven finite state machine that is fairly general and could be adapted to different applications.
<syntaxhighlight lang="c">
#include <stdio.h>
#include <ctype.h>
Line 233 ⟶ 324:
return 0;
}
</syntaxhighlight>
Machine simulation :
<pre>
Line 251 ⟶ 342:
=={{header|C++}}==
<syntaxhighlight lang="c">
#include <map>
Line 416 ⟶ 507:
}
}
</syntaxhighlight>
{{out}}
Line 442 ⟶ 533:
=={{header|D}}==
{{trans|Kotlin}}
<
import std.range;
import std.stdio;
Line 506 ⟶ 597:
void main() {
fsm();
}</
=={{header|Delphi}}==
{{Trans|Go}}
<syntaxhighlight lang="delphi">
program Finite_state_machine;
Line 595 ⟶ 686:
begin
fsm;
end.</
=={{header|FreeBASIC}}==
{{trans|Phix}}
<
READY
WAITING
Line 647 ⟶ 738:
End Select
Loop
Sleep</
{{out}}
<pre>
Line 655 ⟶ 746:
=={{header|Go}}==
{{trans|Kotlin}}
<
import (
Line 754 ⟶ 845:
func main() {
fsm()
}</
{{out}}
Line 778 ⟶ 869:
=={{header|Groovy}}==
{{trans|Java}}
<
private enum State {
Ready(true, "Deposit", "Quit"),
Line 826 ⟶ 917:
}
}
}</
=={{header|Haskell}}==
<
import Data.Maybe
import Control.Monad
Line 900 ⟶ 991:
, Implicit "Refunding" "Ready" ]
finishStates = ["Exit"]
</syntaxhighlight>
=={{header|J}}==
Line 906 ⟶ 997:
This seems to be what the current draft task asks for:
<syntaxhighlight lang="text">NB. FSM builder:
explicit=: {{
states=: ~. states,x;y
Line 926 ⟶ 1,017:
Snm=: statename=: {{ ;:inv m{states }}
Tnm=: transitionname=: {{ ;:inv m{transitions }}
implicits=: {{ r=.'' while. next '' do. r=.r, current end. }}</
With the above implementation, the task example would look like:
<
start 'ready'
'ready' 'deposit'explicit 'waiting'
Line 958 ⟶ 1,049:
echo 'implicit transition to: ',i statename
end.
}}</
More advanced examples might put the FSM in a locale (allowing for multiple, independent FSMs), add callbacks and/or parameterization on transitions, or maybe include hardware specific code.
=={{header|Java}}==
<
public class FiniteStateMachine {
Line 1,014 ⟶ 1,105:
}
}
}</
<pre>[Deposit, Quit]
> Deposit
Line 1,033 ⟶ 1,124:
=={{header|JavaScript}}==
===On browser using blocking window methods===
<
var states = [{
'name': 'Ready',
Line 1,101 ⟶ 1,192:
}
}
</syntaxhighlight>
=={{header|jq}}==
{{works with|jq}}
'''Also works with gojq and fq''' provided the line defining
keys_unsorted is uncommented.
In this entry, we adopt an approach which emphasizes
separating code from data: we define a format for
representing state-transition tables as JSON objects,
which can be stored for example in separate files;
and we illustrate one possible FSM engine for
animating such state-transition tables.
The format of the JSON object specifying a state-transition table is
as follows, it being assumed that each "state" has a distinct
description as a JSON string:
* each top-level key represents a state of the FSM, with "exit" meaning stop;
* the value of each top-level key is another JSON object, which we will refer to as the trigger dictionary;
* each trigger dictionary consists of one or more key-value pairs, in which the "key" is the name of a trigger and the value is the name of a state.
Triggers can be of three kinds:
1. external (corresponding to external inputs)
2. automatic (corresponding to determinate internal transitions)
3. indeterminate (corresponding to non-determinism)
For external transitions, the keys should be non-empty strings that do not match "^[0-9]+ ".
For automatic transitions, the trigger object should have "" as its only key.
For indeterminate transitions, the trigger object should have keys matching the regex "^[0-9]+ "
The FSM engine presented here is intended to allow a person to provide
the "external inputs" as well as to pace automatic transitions and
to simulate the indeterminate transitions. In general, a menu of valid
input choices is presented, and the first match of the response with
these options determines the state transition. In addition, "?" as a
user input is recognized as a request for help.
'''fsm.json'''
<syntaxhighlight lang=jq>
{
"ready": {
"deposit": "waiting",
"quit": "exit"
},
"waiting": {
"select": "dispense",
"refund": "refunding"
},
"dispense": {
"confirm": "confirming",
"refund": "refunding"
},
"refunding": {
"1 REFUND MONEY": "ready",
"2 SORRY": "ready"
},
"confirming": {
"": "ready"
}
}
</syntaxhighlight>
'''fsm.jq'''
<syntaxhighlight lang=jq>
# Uncomment the following line if using gojq or fq:
# def keys_unsorted: keys;
# next($action) determines the next state.
# Global: $fsm (the transition-table)
# $action specifies an action, which can be abbreviated: the first possible match is selected.
# Input: {state}
def next($action):
($fsm[.state] | keys_unsorted) as $keys
| if ($action|length) == 0
then if $keys|index("") then fsm[.state][""]
else null
end
else (first($keys[] | select( startswith($action) )) // null) as $k
| if $k then fsm[.state][$k] else null end
end;
def start: {"state": "ready"};
# The FSM engine - progress from state to state based on user input
def progress:
def options: fsm[.state]|keys_unsorted;
def prompt:
options
| if length == 1 and .[0]=="" then "Enter anything to proceed."
elif .[0]|test("^[0-9]+ ") then "options: \(.) (simulated non-deterministic transition)"
else "options: \(.)"
end;
def help:
options
| if length == 1 and .[0]=="" then "(internal state transition awaiting your input)"
elif .[0]|startswith("1 ") then "(simulated NDFSM awaiting your input in the form of an initial substring): \(.)"
else
"Make a selection by typing an initial substring of the option you wish to select: \(.)"
end;
start
| label $out
| "Initial state: \(.state)\nMake your selection (at least one letter) from these options: \(options))",
foreach inputs as $in (.;
.previous=.state
| .error = null
| if $in == "?" then .error = true #
else next($in) as $next
| if $next then .state=$next else .error = "try again or enter ? for help" end
end;
if .error == true then help
elif .error then .error
elif .state == "exit" then break $out
else
"\(.previous) + \($in) => \(.state)",
prompt
end
) ;
progress
</syntaxhighlight>
'''Illustrative Transcript''':
<pre>
$ jq -nRr --argfile fsm fsm.json -f fsm.jq
Initial state: ready
Make your selection (at least one letter) from these options: ["deposit","quit"])
?
Make a selection by typing an initial substring of the option you wish to select: ["deposit","quit"]
d
ready + d => waiting
options: ["refund","select"]
s
waiting + s => dispense
options: ["confirm","refund"]
c
dispense + c => confirming
Enter anything to proceed.
confirming + => ready
options: ["deposit","quit"]
d
ready + d => waiting
options: ["refund","select"]
r
waiting + r => refunding
options: ["1 REFUND MONEY","2 SORRY"] (simulated non-deterministic transition)
1
refunding + 1 => ready
options: ["deposit","quit"]
q
</pre>
=={{header|Julia}}==
<
struct Ready <: State
Line 1,185 ⟶ 1,429:
runsim(Ready())
</
<pre>
Vending machine is ready. (q)uit, (d)eposit: d
Line 1,198 ⟶ 1,442:
=={{header|Kotlin}}==
<
enum class State { READY, WAITING, EXIT, DISPENSE, REFUNDING }
Line 1,254 ⟶ 1,498:
fun main(args: Array<String>) {
fsm()
}</
Sample input/output:
Line 1,277 ⟶ 1,521:
=={{header|Nim}}==
{{trans Kotlin}}
<
type State {.pure.} = enum Ready, Waiting, Exit, Dispense, Refunding
Line 1,321 ⟶ 1,565:
break
fsm()</
{{out}}
Line 1,341 ⟶ 1,585:
=={{header|Ol}}==
<
(import (scheme read))
Line 1,392 ⟶ 1,636:
; run
(state-machine states 'ready)
</syntaxhighlight>
{{Out}}
<pre>
Line 1,424 ⟶ 1,668:
</pre>
<syntaxhighlight lang="pascal">
{
fsm1.pas
Line 1,681 ⟶ 1,925:
end.
</syntaxhighlight>
Line 1,757 ⟶ 2,001:
=={{header|Perl}}==
Added a dummy input called "IMPLICIT" that does not actually require input but automatically transitions to next state.
<
use strict; # https://rosettacode.org/wiki/Finite_state_machine
Line 1,793 ⟶ 2,037:
waiting REFUND refunding take the refund
dispense REMOVE ready Thank You
refunding IMPLICIT ready</
{{out}}
<pre>
Line 1,821 ⟶ 2,065:
{{libheader|Phix/online}}
You can run this online [http://phix.x10.mx/p2js/fsm.htm here].
<!--<
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\Finite_State_Machine.exw
Line 1,900 ⟶ 2,144:
<span style="color: #7060A8;">IupHide</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<!--</
=={{header|PicoLisp}}==
Non-interactive random switch between states.
<
(de atm NIL
(state '(ready)
Line 1,918 ⟶ 2,162:
(nil (prinl "quit")) ) ) )
(do 3
(while (atm)) )</
{{out}}
<pre>
Line 1,928 ⟶ 2,172:
=={{header|Prolog}}==
<
state(ready, quit, exit).
state(waiting, select, dispense).
Line 1,952 ⟶ 2,196:
act(NextState).
print_message(State) :- message(State, Message), format(Message).</
{{out}}
<pre>
Line 1,974 ⟶ 2,218:
=={{header|Python}}==
{{works with|Python 3}}
<
Actually two of them. The main FSM described in the task and a second one of the Acceptor variety described on
the WP page to get the input from the user.
Line 2,033 ⟶ 2,277:
if __name__ == "__main__":
finite_state_machine('ready','q')
</syntaxhighlight>
{{out}}
<pre>
Line 2,048 ⟶ 2,292:
=={{header|Racket}}==
<
(define states
Line 2,078 ⟶ 2,322:
(let/ec quit
(with-input-from-string "deposit select remove deposit refund quit"
(λ () (machine states void read quit)))))</
{{out}}
<pre>CURRENT STATE: ready
Line 2,099 ⟶ 2,343:
(formerly Perl 6)
<syntaxhighlight lang="raku"
class StateMachine {
Line 2,174 ⟶ 2,418:
$machine.add-transition("refunding", "ready");
$machine.run("ready");</
=={{header|REXX}}==
Line 2,188 ⟶ 2,432:
::* a mixture of uppercase and lowercase text is used for the output messages
::* messages have extra blanks for readability (and options are spelled out)
<
10: say "Press D (deposit) or Q (quit)" /*display a prompt (message) to term. */
20: $=inkey(); upper $ /*since this a terminal, uppercase KEY.*/
Line 2,210 ⟶ 2,454:
140: say "Refunded" /*display what action just happened. */
signal 10 /*go & re-start process (ready state). */</
{{out|output|text= when using (pressing) the exact same input(s) as the '''BASIC''' entry: <tt> D R D S R Q </tt>}}
<pre>
Line 2,231 ⟶ 2,475:
works withooRexx (and any other REXX).
key and Enter must be pressed-
<
10: k=inkey('D (deposit) or Q (quit)','DQ')
if k=="D" then signal 50 /*Is response a "D" ? Process deposit.*/
Line 2,258 ⟶ 2,502:
Say 'Invalid key, try again.'
End
Return k</
{{out}}
<pre>Press D (deposit) or Q (quit) and Enter
Line 2,278 ⟶ 2,522:
'''[dependencies]'''<br>
methods-enum = "0.2.4"
<
Ready,
Waiting,
Line 2,343 ⟶ 2,587:
std::io::stdin().read_line(&mut text).unwrap_or(0);
text.chars().next().unwrap_or('\x0d')
}</
{{out}}
<pre>Ready: d - deposit / q - quit
Line 2,363 ⟶ 2,607:
=={{header|Tcl}}==
Using a nested dict where the leafs contain the output state corresponding to an action, and empty actions are implicit transitions. Would be marginally cleaner using a do..while proc.
<
ready {deposit waiting quit exit} \
waiting {select dispense refund refunding} \
Line 2,390 ⟶ 2,634:
set state [dict get $fsm $state {}]
}
}</
{{out}}
<pre>$ tclsh fsm.tcl
Line 2,410 ⟶ 2,654:
=={{header|VBA}}==
{{trans|Phix}}
<
READY
WAITING
Line 2,461 ⟶ 2,705:
End Select
Loop
End Sub</
<pre>Machine is READY. (D)eposit or (Q)uit :
D
Line 2,481 ⟶ 2,725:
{{trans|Kotlin}}
{{libheader|Wren-str}}
<
import "io" for Stdin, Stdout
Line 2,532 ⟶ 2,776:
}
fsm.call()</
{{out}}
Line 2,552 ⟶ 2,796:
(D)ispense or (Q)uit : q
OK, quitting
</pre>
=={{header|XPL0}}==
<syntaxhighlight lang "XPL0">int State, Trans, Table, Msg;
def \State\ Ready, Waiting, Dispense, Refunding, Exit;
def \Trans\ Deposit, Select, Refund, Collect, Quit; \State:
[Table:=[[Waiting, Ready, Ready, Ready, Exit], \Ready
[Waiting, Dispense, Refunding, Waiting, Waiting], \Waiting
[Dispense, Dispense, Dispense, Ready, Dispense], \Dispense
[Ready, Ready, Ready, Ready, Ready], \Refunding
[Exit, Exit, Exit, Exit, Exit]]; \Exit
State:= Ready;
loop [Msg:= ["Ready, choose (D)eposit or (Q)uit: ",
"Waiting, choose (S)elect or (R)efund: ",
"Dispensing, please (C)ollect product: ",
"Refunding, please collect refund.",
"Shutting down."];
Text(0, Msg(State));
case State of
Exit: quit;
Refunding: Trans:= Refund \implicit transition
other case ChIn(1) of \explicit transitions
^D,^d: Trans:= Deposit;
^S,^s: Trans:= Select;
^R,^r: Trans:= Refund;
^C,^c: Trans:= Collect;
^Q,^q: Trans:= Quit
other []; \illegal entries don't change state
CrLf(0);
State:= Table(State, Trans);
];
CrLf(0);
]</syntaxhighlight>
{{out}}
<pre>
Ready, choose (D)eposit or (Q)uit: D
Waiting, choose (S)elect or (R)efund: S
Dispensing, please (C)ollect product: C
Ready, choose (D)eposit or (Q)uit: D
Waiting, choose (S)elect or (R)efund: R
Refunding, please collect refund.
Ready, choose (D)eposit or (Q)uit: Q
Shutting down.
</pre>
Line 2,558 ⟶ 2,845:
If we need true state to state hops, we could use tail recursion (another name for goto).
<
var bank=0, item=Void;
fcn deposit(coin){ bank=coin }
Line 2,573 ⟶ 2,860:
}
Vault.add(FSM); // put class FSM where I can find it</
<
program=program.replace("(",".fp("); // deposit(10)-->deposit.fp(10)
a,b,p := 0,0,Sink("class P(FSM){ state(); ");
Line 2,582 ⟶ 2,869:
// println(program); // WTH did I just do?
Compiler.Compiler.compileText(program)(); // compile and run our little FSM
}</
<
The above is converted to:
<
state();
act(select.fp());
Line 2,592 ⟶ 2,879:
act( select.fp("snickers"));
act( take.fp());
}</
The .fp() is function application (ie deferred execution) so I can extract the
function name and print it.
|