-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 1ab8889
Showing
19 changed files
with
2,306 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.DS_Store | ||
python/.DS_Store | ||
python/__pycache__/ | ||
python/test/__pycache__/ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
.PHONY: all run-rust run-bash run-python run-js run-ruby | ||
|
||
all: run-rust run-bash run-python run-js run-ruby | ||
|
||
run-rust: | ||
@echo --- | ||
@echo "Running Rust implementation..." | ||
cargo run --manifest-path rust/Cargo.toml | ||
|
||
run-bash: | ||
@echo --- | ||
@echo "Running Bash implementation..." | ||
bash bash/main.sh | ||
|
||
run-python: | ||
@echo --- | ||
@echo "Running Python implementation..." | ||
python3 python/main.py | ||
|
||
run-js: | ||
@echo --- | ||
@echo "Running JavaScript implementation..." | ||
node javascript/src/main.js | ||
|
||
run-ruby: | ||
@echo --- | ||
@echo "Running Ruby implementation..." | ||
ruby ruby/main.rb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Coffee Machine State Machine | ||
|
||
This project demonstrates the implementation of a coffee vending machine using state machines | ||
in different programming languages. | ||
|
||
[](https://pflow.dev/p/zb2rhjeJ8bKSGRDHYv1e4Ap6wZrXvF6hqQkGYW7B1hk1KBsWa/) | ||
|
||
Click the image above to view the state machine in the [PFlow](https://pflow.dev) editor. | ||
|
||
## Contributing | ||
|
||
Contributions are welcome! Feel free to add new implementations in different languages or improve existing ones. | ||
|
||
## State Machine Implementation | ||
|
||
The state machine is implemented using the following components: | ||
- **States**: Represent the different states of the coffee machine (e.g., `BoiledWater`, `GroundCoffee`, `CoffeeInPot`). | ||
- **Transitions**: Represent the actions that cause state changes (e.g., `BrewCoffee`, `PourCoffee`). | ||
- **Arrows**: Define the allowed transitions between states. | ||
- **Guards**: Ensure that certain transitions only occur when specific conditions are met. | ||
|
||
## Languages | ||
|
||
The state machine is implemented in multiple programming languages to compare their behavior and ensure consistency. | ||
Each implementation follows the same Petri net model. | ||
|
||
### Other Languages | ||
|
||
Implementations in other languages (e.g., Python, Java, C++) will be added in their respective directories. | ||
Each implementation will follow the same structure and logic as the Rust implementation. | ||
|
||
## Running the State Machine | ||
|
||
To run all samples just use | ||
``` | ||
make all | ||
``` | ||
|
||
To run a specific language use | ||
``` | ||
make run-bash | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
#!/bin/bash | ||
|
||
states=( | ||
"Water:1" | ||
"BoiledWater:0" | ||
"CoffeeBeans:1" | ||
"GroundCoffee:0" | ||
"Filter:1" | ||
"CoffeeInPot:0" | ||
"Pending:1" | ||
"Sent:0" | ||
"Payment:0" | ||
"Cup:1" | ||
) | ||
|
||
actions=( | ||
"BoilWater" | ||
"GrindBeans" | ||
"BrewCoffee" | ||
"PourCoffee" | ||
"Send" | ||
"Credit" | ||
) | ||
|
||
arrows=( | ||
"Water > BoilWater" | ||
"BoilWater > BoiledWater" | ||
"CoffeeBeans > GrindBeans" | ||
"GrindBeans > GroundCoffee" | ||
"BoiledWater > BrewCoffee" | ||
"GroundCoffee > BrewCoffee" | ||
"Filter > BrewCoffee" | ||
"BrewCoffee > CoffeeInPot" | ||
"CoffeeInPot > PourCoffee" | ||
"Cup > PourCoffee" | ||
"Pending > Send" | ||
"Send > Sent" | ||
"Sent > Credit" | ||
"Credit > Payment" | ||
) | ||
|
||
guards=( | ||
"Payment > PourCoffee" | ||
) | ||
|
||
# Print the current state as a set | ||
function print_state() { | ||
local output="{" | ||
for state in "${states[@]}"; do | ||
IFS=":" read -r name value <<<"$state" | ||
if [[ $value == "1" ]]; then | ||
output+=" $name," | ||
fi | ||
done | ||
output="${output%,} }" | ||
echo "$output" | ||
} | ||
|
||
# Check if the element is present in the current state | ||
function has_state() { | ||
for state in "${states[@]}"; do | ||
IFS=":" read -r name value <<<"$state" | ||
if [[ $name == "$1" && $value == "1" ]]; then | ||
return 0 | ||
fi | ||
done | ||
return 1 | ||
} | ||
|
||
# Set the state of a given element | ||
function set_state() { | ||
for i in "${!states[@]}"; do | ||
IFS=":" read -r name value <<<"${states[$i]}" | ||
if [[ $name == "$1" ]]; then | ||
states[$i]="$name:$2" | ||
fi | ||
done | ||
return 0 | ||
} | ||
|
||
function guard_fails() { | ||
for guard in "${guards[@]}"; do | ||
local from to | ||
IFS=" > " read -r from to <<<"$guard" | ||
if [[ "$from" == "$1" ]]; then | ||
if has_state "$to"; then | ||
return 0 | ||
fi | ||
fi | ||
if [[ "$to" == "$1" ]]; then | ||
if ! has_state "$from"; then | ||
return 0 | ||
fi | ||
fi | ||
|
||
done | ||
return 1 | ||
} | ||
|
||
# Transform the state based on the action | ||
function transform() { | ||
if guard_fails "$1"; then | ||
return 1 | ||
fi | ||
|
||
local arrow | ||
|
||
for arrow in "${arrows[@]}"; do | ||
IFS=" > " read -r from to <<<"$arrow" | ||
if [[ "$from" == "$1" ]]; then # action -> state | ||
if has_state "$to"; then | ||
return 1 # Invalid output | ||
else | ||
set_state $to 1 | ||
fi | ||
fi | ||
if [[ $to == "$1" ]]; then # state -> action | ||
if has_state "$from"; then | ||
set_state "$from" 0 | ||
else | ||
return 1 # Insufficient input | ||
fi | ||
fi | ||
done | ||
return 0 | ||
} | ||
|
||
# Check if the action can be performed based on the current state | ||
function can_transform() { | ||
if guard_fails "$1"; then | ||
return 1 | ||
fi | ||
|
||
local arrow | ||
for arrow in "${arrows[@]}"; do | ||
IFS=" > " read -r from to <<<"$arrow" | ||
if [[ $from == "$1" ]]; then # action -> state | ||
if has_state "$to"; then | ||
return 1 # Invalid output | ||
fi | ||
fi | ||
if [[ $to == "$1" ]]; then # state -> action | ||
if ! has_state "$from"; then | ||
return 1 # Insufficient input | ||
fi | ||
fi | ||
done | ||
} | ||
|
||
# Main function - runs the process by executing the actions | ||
# for the current state until no more actions are possible | ||
function main() { | ||
local step=1 | ||
echo "step #0: Initial state" | ||
print_state | ||
while true; do | ||
local transformed=false | ||
for action in "${actions[@]}"; do | ||
if can_transform "$action"; then | ||
transform "$action" | ||
echo "step #$step: $($action)" | ||
transformed=true | ||
step=$((step + 1)) | ||
break | ||
fi | ||
done | ||
if ! $transformed; then | ||
break | ||
else | ||
print_state | ||
fi | ||
done | ||
} | ||
|
||
function BoilWater { | ||
echo "Boiling Water" | ||
} | ||
|
||
function GrindBeans { | ||
echo "Grinding Beans" | ||
} | ||
|
||
function BrewCoffee { | ||
echo "Brewing Coffee" | ||
} | ||
|
||
function PourCoffee { | ||
echo "Pouring Coffee" | ||
} | ||
|
||
function Send { | ||
echo "Sending Payment" | ||
} | ||
|
||
function Credit { | ||
echo "Crediting Payment" | ||
} | ||
|
||
main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/stackdump/pflow-polyglot/golang | ||
|
||
go 1.22.4 |
Oops, something went wrong.