Last active
June 4, 2020 08:09
-
-
Save andhieka/4a8c5eea916e87a77378e5110840d397 to your computer and use it in GitHub Desktop.
MysteryGame - Completed with State Pattern
This file contains hidden or 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
import 'dart:io'; | |
abstract class GameState { | |
String getPrompt(); | |
void process(String input, MysteryGame game); | |
} | |
//#region Concrete states | |
class TheKitchenGameState extends GameState { | |
static const List<String> KITCHEN_ACTION_LIST = [ | |
'chop', | |
'chop', | |
'chop', | |
'chop', | |
'chop', | |
'fry', | |
'serve', | |
]; | |
int completedKitchenActionIndex = 0; | |
@override | |
String getPrompt() { | |
if (completedKitchenActionIndex == 0) { | |
return 'Welcome to The Kitchen. Do your actions without mistake!'; | |
} | |
} | |
@override | |
void process(String input, MysteryGame game) { | |
if (input == KITCHEN_ACTION_LIST[completedKitchenActionIndex]) { | |
completedKitchenActionIndex++; | |
if (completedKitchenActionIndex == KITCHEN_ACTION_LIST.length) { | |
game.state = DanceStudioGameState(); | |
} | |
} else { | |
game.state = DeadGameState(); | |
} | |
} | |
} | |
class DanceStudioGameState extends GameState { | |
static const List<String> DANCE_ACTIONS = [ | |
'left', | |
'right', | |
'jump', | |
'jump', | |
]; | |
int completedDanceActionIndex = 0; | |
@override | |
String getPrompt() { | |
if (completedDanceActionIndex == 0) { | |
return 'Welcome to the Dance Studio! Do the secret dance to pass.'; | |
} | |
return null; | |
} | |
@override | |
void process(String input, MysteryGame game) { | |
if (input == DANCE_ACTIONS[completedDanceActionIndex]) { | |
completedDanceActionIndex++; | |
if (completedDanceActionIndex == DANCE_ACTIONS.length) { | |
game.state = MusicStudioGameState(); | |
} | |
} else { | |
game.state = DeadGameState(); | |
} | |
} | |
} | |
class MusicStudioGameState extends GameState { | |
DateTime lastInputTime; | |
int baseIntervalMs; | |
static const List<String> NOTES = [ | |
'c', 'c', 'd', 'c', 'f', 'e' | |
]; | |
int completedNoteIndex = 0; | |
int retriesAllowed = 3; | |
@override | |
String getPrompt() { | |
if (completedNoteIndex == 0) { | |
return "Sing happy birthday in C! (pretend all notes are quarter notes)"; | |
} | |
return null; | |
} | |
@override | |
void process(String input, MysteryGame game) { | |
if (input == NOTES[completedNoteIndex]) { | |
if (_isTempoAcceptable()) { | |
completedNoteIndex++; | |
lastInputTime = DateTime.now(); | |
if (completedNoteIndex == NOTES.length) { | |
game.state = SuccessGameState(); | |
} | |
} else { | |
print('Wrong tempo!'); | |
_reset(); | |
} | |
} else { | |
if (retriesAllowed == 0) { | |
game.state = DeadGameState(); | |
} else { | |
_reset(); | |
} | |
} | |
} | |
void _reset() { | |
retriesAllowed--; | |
completedNoteIndex = 0; | |
baseIntervalMs = null; | |
lastInputTime = null; | |
} | |
bool _isTempoAcceptable() { | |
if (lastInputTime == null) { | |
// no need to check first note | |
return true; | |
} | |
DateTime now = DateTime.now(); | |
int intervalInMs = now.millisecondsSinceEpoch - lastInputTime.millisecondsSinceEpoch; | |
if (baseIntervalMs == null) { | |
// set base tempo on second note | |
baseIntervalMs = intervalInMs; | |
print("(Base tempo = ${60 / intervalInMs * 1000})"); | |
return true; | |
} | |
return baseIntervalMs * 0.75 < intervalInMs && intervalInMs < baseIntervalMs * 1.25; | |
} | |
} | |
class StartGameState extends GameState { | |
@override | |
String getPrompt() { | |
return 'Type ready to start the game'; | |
} | |
@override | |
void process(String input, MysteryGame game) { | |
if (input == 'ready') { | |
game.state = TheKitchenGameState(); | |
} | |
} | |
} | |
class SuccessGameState extends GameState { | |
@override | |
String getPrompt() { | |
return 'Congratulations! You are successful 🎉'; | |
} | |
@override | |
void process(String input, MysteryGame game) { | |
if (input == 'RIP') { | |
game.state = DeadGameState(); | |
} | |
} | |
} | |
class DeadGameState extends GameState { | |
@override | |
String getPrompt() { | |
return 'You are dead. Like this game? Feel free to retry.'; | |
} | |
@override | |
void process(String input, MysteryGame game) { | |
if (input == 'retry') { | |
game.state = StartGameState(); | |
} | |
} | |
} | |
//#endregion | |
class MysteryGame { | |
GameState state; | |
MysteryGame() { | |
state = StartGameState(); | |
} | |
String getPrompt() { | |
return state.getPrompt(); | |
} | |
void process(String input) { | |
return state.process(input, this); | |
} | |
} | |
void main() { | |
print('MysteryMaze v1.0'); | |
print('---'); | |
MysteryGame game = MysteryGame(); | |
while (true) { | |
if (game.getPrompt() != null) { | |
print(game.getPrompt()); | |
} | |
String input = stdin.readLineSync(); | |
if (input == 'exit') { | |
break; | |
} else { | |
game.process(input); | |
} | |
} | |
print('Good bye! Come MysteryMaze again soon!'); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment