Back to project page it.alcacoop.fourinaline.
The source code is released under:
GNU General Public License
If you think the Android project it.alcacoop.fourinaline listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/** ################################################################## # FOUR IN A LINE MOBILE # ################################################################## # # # Authors: Domenico Martella - Francesco Valente # # E-mail: info@alcacoop.it # # Date: 18/10/2013 # # # ################################################################## # # # Copyright (C) 2013 Alca Societa' Cooperativa # # # # This file is part of FOUR IN A LINE MOBILE. # # FOUR IN A LINE MOBILE is free software: you can redistribute # # it and/or modify it under the terms of the GNU General # # Public License as published by the Free Software Foundation, # # either version 3 of the License, or (at your option) # # any later version. # # # # FOUR IN A LINE MOBILE is distributed in the hope that it # # will be useful, but WITHOUT ANY WARRANTY; without even the # # implied warranty of MERCHANTABILITY or FITNESS FOR A # # PARTICULAR PURPOSE. See the GNU General Public License # # for more details. # # # # You should have received a copy of the GNU General # # Public License v3 along with this program. # # If not, see <http://http://www.gnu.org/licenses/> # # # ################################################################## **///from ww w . j a v a 2s.co m /** @startuml null --> MAIN_MENU MAIN_MENU --> MAIN_MENU : BUTTON_CLICKED MAIN_MENU --> MATCH_OPTIONS MATCH_OPTIONS --> MATCH_OPTIONS : BUTTON_CLICKED MATCH_OPTIONS --> INIT_GAME INIT_GAME --> INIT_GAME : START_GAME INIT_GAME --> LOCAL_TURN LOCAL_TURN --> LOCAL_TURN : CLICKED_COL LOCAL_TURN --> LOCAL_TURN : MOVE_END LOCAL_TURN --> AI_TURN AI_TURN --> AI_TURN : AI_EVALUETED AI_TURN --> AI_TURN : MOVE_END AI_TURN --> LOCAL_TURN LOCAL_TURN --> CHECK_END_MATCH CHECK_END_MATCH --> CHECK_END_MATCH : GAME_TERMINATED CHECK_END_MATCH --> CHECK_END_MATCH : BOARD_RESETTED CHECK_END_MATCH --> MAIN_MENU @enduml * * Result of: * $> grep -i "PLANTUML" fsm_single | sed 's/PLANTUML://' * on the output */ // SIMULATED GAME STATE MACHINE // From: http://vanillajava.blogspot.com/2011/06/java-secret-using-enum-as-state-machine.html package it.alcacoop.fourinaline.fsm; import it.alcacoop.fourinaline.FourInALine; import it.alcacoop.fourinaline.actors.UIDialog; import it.alcacoop.fourinaline.fsm.FSM.Events; import it.alcacoop.fourinaline.gservice.GServiceClient; import it.alcacoop.fourinaline.gservice.GServiceMessages; import it.alcacoop.fourinaline.layers.GameScreen; import it.alcacoop.fourinaline.logic.MatchState; import it.alcacoop.fourinaline.utils.AchievementsManager; import it.alcacoop.fourinaline.utils.ELORatingManager; import java.util.Random; import org.gojul.fourinaline.model.AlphaBeta; import com.badlogic.gdx.Gdx; interface Context { State state(); void state(State state); } interface State { boolean processEvent(Context ctx, Events evt, Object params); void enterState(Context ctx); void exitState(Context ctx); } // MAIN FSM public class FSM implements Context { private static long waitTime; public enum Events { NOOP, RESIGN_GAME, BUTTON_CLICKED, GAME_TERMINATED, BOARD_RESETTED, MOVE_END, CLICKED_COL, AI_EVALUETED, START_GAME, LEAVE_GAME, LEAVE_MATCH, GSERVICE_READY, GSERVICE_INIT_RATING, GSERVICE_HANDSHAKE, GSERVICE_BYE, GSERVICE_MOVES, PERFORMED_MOVE, GSERVICE_ABANDON, OPPONENT_LEAVE_OR_RESIGN, GSERVICE_ERROR, GSERVICE_CHATMSG } public enum States implements State { MAIN_MENU { @Override public void enterState(Context ctx) { FourInALine.Instance.setScreen(FourInALine.Instance.menuScreen); String invitationId = FourInALine.Instance.nativeFunctions.gservicePendingNotificationAreaInvitation(); if (!invitationId.equals("")) { FourInALine.Instance.nativeFunctions.gserviceAcceptInvitation(invitationId); } } @Override public boolean processEvent(Context ctx, Events evt, Object params) { switch (evt) { case LEAVE_GAME: if ((Boolean)params) Gdx.app.exit(); break; case BUTTON_CLICKED: String btn = ((String)params); FourInALine.Instance.snd.playButton(); FourInALine.Instance.vibrate(80); if (btn.equals("SINGLE PLAYER")) { MatchState.matchType = 0; FourInALine.Instance.fsm.state(States.MATCH_OPTIONS); } else if (btn.equals("TWO PLAYERS")) { MatchState.matchType = 1; FourInALine.Instance.fsm.state(States.MATCH_OPTIONS); } else if (btn.equals("ONLINE MULTIPLAYER")) { if (FourInALine.Instance.nativeFunctions.isNetworkUp()) { MatchState.matchType = 2; FourInALine.Instance.nativeFunctions.gserviceStartRoom(); } else { UIDialog.getFlashDialog(Events.NOOP, "Network is down - Multiplayer not available"); } } else if (btn.equals("OPTIONS")) { FourInALine.Instance.fsm.state(States.GAME_OPTIONS); } else if (btn.equals("ABOUT..")) { UIDialog.getAboutDialog(); } else if (btn.equals("REMOVE ADS")) { FourInALine.Instance.nativeFunctions.inAppBilling(); } else if (btn.equals("RATE IT!")) { FourInALine.Instance.nativeFunctions.openURL("https://play.google.com/store/apps/details?id=it.alcacoop.fourinaline"); } break; default: return false; } return true; } }, GAME_OPTIONS { @Override public void enterState(Context ctx) { FourInALine.Instance.setScreen(FourInALine.Instance.optionsScreen); } @Override public boolean processEvent(Context ctx, Events evt, Object params) { switch (evt) { case BUTTON_CLICKED: String btn = ((String)params); if (btn.equals("BACK")) { FourInALine.Instance.fsm.back(); } break; default: return false; } return true; } }, MATCH_OPTIONS { @Override public void enterState(Context ctx) { FourInALine.Instance.setScreen(FourInALine.Instance.matchOptionsScreen); } @Override public boolean processEvent(Context ctx, Events evt, Object params) { switch (evt) { case BUTTON_CLICKED: String btn = ((String)params); if (btn.equals("BACK")) { FourInALine.Instance.fsm.back(); } else if (btn.equals("PLAY")) { MatchState.firstGame = true; FourInALine.Instance.fsm.state(States.INIT_GAME); } break; default: return false; } return true; } }, INIT_GAME { @Override public void enterState(Context ctx) { if (MatchState.matchType == 2) { FourInALine.Instance.setScreen(FourInALine.Instance.gameScreen); FourInALine.Instance.board.initMatch(MatchState.whoStart); } else { int[] a = { 1, 2 }; if (MatchState.firstGame) { FourInALine.Instance.setScreen(FourInALine.Instance.gameScreen); MatchState.whoStart = new Random().nextInt(2) + 1; } else { MatchState.whoStart = ((MatchState.whoStart - 1) == 0) ? a[1] : a[0]; } FourInALine.Instance.board.initMatch(MatchState.whoStart); } super.enterState(ctx); } @Override public boolean processEvent(Context ctx, Events evt, Object params) { if (evt == Events.START_GAME) { System.out.println("WHO: " + MatchState.whoStart); switch (MatchState.matchType) { case -1: // SIMULATION FourInALine.Instance.fsm.state(AI_TURN); break; case 0: // SINGLE PLAYER ELORatingManager.getInstance().setRatings(AlphaBeta.ratings[MatchState.AILevel - 1]); if (MatchState.whoStart == 1) FourInALine.Instance.fsm.state(LOCAL_TURN); else FourInALine.Instance.fsm.state(AI_TURN); break; case 1: // TWO PLAYER FourInALine.Instance.fsm.state(LOCAL_TURN); break; case 2: // MULTIPLAYER if (MatchState.whoStart == 1) FourInALine.Instance.fsm.state(LOCAL_TURN); else FourInALine.Instance.fsm.state(REMOTE_TURN); break; default: break; } return true; } return false; } }, LOCAL_TURN { @Override public void enterState(Context ctx) { if (MatchState.winner == -1) { FourInALine.Instance.gameScreen.highlightPlayer(MatchState.currentPlayer); } FourInALine.Instance.gameScreen.showThinking(false); } @Override public boolean processEvent(Context ctx, Events evt, Object params) { switch (evt) { case CLICKED_COL: FourInALine.Instance.board.play((Integer)params); break; case MOVE_END: if (MatchState.matchType == 0) FourInALine.Instance.fsm.state(AI_TURN); else if (MatchState.matchType == 1) FourInALine.Instance.fsm.state(LOCAL_TURN); else if (MatchState.matchType == 2) { int col = (Integer)params; FourInALine.Instance.fsm.state(REMOTE_TURN); GServiceClient.getInstance().sendMessage("6 " + col); } break; case LEAVE_MATCH: // LEAVE MATCH if ((Boolean)params) { MatchState.nMatchTo = 0; // DIRTY HACK FourInALine.Instance.fsm.state(CHECK_END_MATCH); if (MatchState.matchType == 2) { GServiceClient.getInstance().sendMessage(GServiceMessages.GSERVICE_ABANDON + " 1"); FourInALine.Instance.fsm.processEvent(Events.GAME_TERMINATED, null); } else { FourInALine.Instance.fsm.processEvent(Events.GAME_TERMINATED, null); } } break; case RESIGN_GAME: // RESIGN MATCH if ((Boolean)params) { MatchState.nMatchTo = 0; // DIRTY HACK FourInALine.Instance.fsm.state(CHECK_END_MATCH); if (MatchState.matchType == 2) { GServiceClient.getInstance().sendMessage(GServiceMessages.GSERVICE_ABANDON + " 2"); FourInALine.Instance.fsm.processEvent(Events.GAME_TERMINATED, null); } else { FourInALine.Instance.fsm.processEvent(Events.GAME_TERMINATED, null); } } break; case OPPONENT_LEAVE_OR_RESIGN: int abandonOrResign = (Integer)params; MatchState.nMatchTo = 0; // DIRTY HACK FourInALine.Instance.gameScreen.highlightPlayer(0); FourInALine.Instance.fsm.state(CHECK_END_MATCH); if (abandonOrResign == 1) { UIDialog.getFlashDialog(Events.GAME_TERMINATED, "Opponent abandoned match"); } else { UIDialog.getFlashDialog(Events.GAME_TERMINATED, "Opponent resigned a game"); } FourInALine.Instance.nativeFunctions.gserviceResetRoom(); break; default: return false; } return true; } }, REMOTE_TURN { @Override public void enterState(Context ctx) { FourInALine.Instance.gameScreen.showThinking(true); if (MatchState.winner == -1) { FourInALine.Instance.gameScreen.highlightPlayer(MatchState.currentPlayer); GServiceClient.getInstance().queue.pull(Events.GSERVICE_MOVES); } } @Override public boolean processEvent(Context ctx, Events evt, Object params) { switch (evt) { case GSERVICE_MOVES: int col = (Integer)params; FourInALine.Instance.board.play((Integer)col); break; case PERFORMED_MOVE: // ctx.board().updatePInfo(); // ctx.board().performNextMove(); break; case MOVE_END: FourInALine.Instance.fsm.state(LOCAL_TURN); break; case LEAVE_MATCH: // LEAVE MATCH if ((Boolean)params) { MatchState.nMatchTo = 0; // DIRTY HACK FourInALine.Instance.fsm.state(CHECK_END_MATCH); GServiceClient.getInstance().sendMessage(GServiceMessages.GSERVICE_ABANDON + " 1"); FourInALine.Instance.fsm.processEvent(Events.GAME_TERMINATED, null); } break; case RESIGN_GAME: // RESIGN MATCH if ((Boolean)params) { MatchState.nMatchTo = 0; // DIRTY HACK FourInALine.Instance.fsm.state(CHECK_END_MATCH); GServiceClient.getInstance().sendMessage(GServiceMessages.GSERVICE_ABANDON + " 2"); FourInALine.Instance.fsm.processEvent(Events.GAME_TERMINATED, null); } break; default: return false; } return true; } }, AI_TURN { @Override public void enterState(Context ctx) { FourInALine.Instance.gameScreen.showThinking(true); if (MatchState.winner == -1) { FourInALine.Instance.gameScreen.highlightPlayer(MatchState.currentPlayer); FourInALine.Instance.board.playAI(); } } @Override public boolean processEvent(Context ctx, Events evt, Object params) { switch (evt) { case AI_EVALUETED: FourInALine.Instance.board.play((Integer)params); break; case MOVE_END: if (MatchState.matchType == -1) FourInALine.Instance.fsm.state(AI_TURN); else FourInALine.Instance.fsm.state(LOCAL_TURN); break; case LEAVE_MATCH: // LEAVE MATCH if ((Boolean)params) { MatchState.nMatchTo = 0; // DIRTY HACK FourInALine.Instance.fsm.state(CHECK_END_MATCH); FourInALine.Instance.fsm.processEvent(Events.GAME_TERMINATED, null); } break; case RESIGN_GAME: // RESIGN MATCH if ((Boolean)params) { MatchState.nMatchTo = 0; // DIRTY HACK FourInALine.Instance.fsm.state(CHECK_END_MATCH); FourInALine.Instance.fsm.processEvent(Events.GAME_TERMINATED, null); } break; default: return false; } return true; } }, GSERVICE { @Override public void enterState(Context ctx) { GServiceClient.getInstance().queue.reset(); MatchState.anScore[0] = 0; MatchState.anScore[1] = 0; MatchState.nMatchTo = 1; GServiceClient.getInstance().sendMessage("2"); GServiceClient.getInstance().queue.pull(Events.GSERVICE_READY); } @Override public boolean processEvent(Context ctx, Events evt, Object params) { switch (evt) { case GSERVICE_READY: GServiceClient.getInstance().sendMessage("8 " + FourInALine.Instance.gameOptionPrefs.getString("multiboard", "0")); GServiceClient.getInstance().queue.pull(Events.GSERVICE_INIT_RATING); break; case GSERVICE_INIT_RATING: double opponentRating = (Double)params; ELORatingManager.getInstance().setRatings(opponentRating); Random gen = new Random(); waitTime = gen.nextLong(); GServiceClient.getInstance().sendMessage("3 " + waitTime + " " + FourInALine.Instance.nativeFunctions.getAppVersionCode()); GServiceClient.getInstance().queue.pull(Events.GSERVICE_HANDSHAKE); break; case GSERVICE_HANDSHAKE: long remoteWaitTime = (Long)params; if (waitTime < remoteWaitTime) { // Tocca a Local Turn MatchState.whoStart = 1; MatchState.currentPlayer = 1; } else { MatchState.whoStart = 2; MatchState.currentPlayer = 2; } FourInALine.Instance.fsm.state(States.INIT_GAME); FourInALine.Instance.fsm.processEvent(Events.START_GAME, null); break; default: return false; } return true; } }, CHECK_END_MATCH { @Override public void enterState(Context ctx) { FourInALine.Instance.gameScreen.showThinking(false); } @Override public boolean processEvent(Context ctx, Events evt, Object params) { switch (evt) { case GAME_TERMINATED: FourInALine.Instance.board.reset(); break; case BOARD_RESETTED: if (MatchState.winner == 1) { AchievementsManager.getInstance().checkAchievements(true); ELORatingManager.getInstance().updateRating(true); } if (MatchState.matchType == 2) { FourInALine.Instance.nativeFunctions.gserviceResetRoom(); FourInALine.Instance.fsm.state(States.MAIN_MENU); } else { MatchState.mCount = 0; if ((MatchState.anScore[0] < MatchState.nMatchTo) && (MatchState.anScore[1] < MatchState.nMatchTo)) { MatchState.firstGame = false; FourInALine.Instance.fsm.state(States.INIT_GAME); FourInALine.Instance.fsm.processEvent(Events.START_GAME, null); } else { FourInALine.Instance.fsm.state(States.MAIN_MENU); } } break; default: return false; } return true; } }, STOPPED { @Override public void enterState(Context ctx) { } }; // DEFAULT IMPLEMENTATION public boolean processEvent(Context ctx, FSM.Events evt, Object params) { return false; } public void enterState(Context ctx) { } public void exitState(Context ctx) { } }; public State currentState; public State previousState; public void start() { state(States.MAIN_MENU); } public void stop() { state(States.STOPPED); } public void restart() { stop(); start(); } public void processEvent(final Events evt, final Object params) { final FSM ctx = this; // System.out.println("PROCESS " + evt + " ON " + state()); System.out.println("PLANTUML:" + currentState + " --> " + state() + " : " + evt); Gdx.app.postRunnable(new Runnable() { @Override public void run() { switch (evt) { case GSERVICE_CHATMSG: FourInALine.Instance.snd.playMessage(); ((GameScreen)FourInALine.Instance.currentScreen).chatBox.appendMessage("Opponent", (String)params, false); break; case GSERVICE_ERROR: // Se la partita in corso if (MatchState.winner == -1) { int errorCode = (Integer)params; String message = ""; switch (errorCode) { case 0: message = "Network error: opponent disconnected!"; break; case 1: message = "Network Error: you disconnected!"; break; case 2: message = "Match stopped. You have to reinvite!"; break; } if (FourInALine.Instance.currentScreen instanceof GameScreen) { ctx.state(States.CHECK_END_MATCH); UIDialog.getFlashDialog(Events.GAME_TERMINATED, message); } } break; case GSERVICE_BYE: // ctx.state(States.MAIN_MENU); break; default: state().processEvent(ctx, evt, params); break; } } }); } public State state() { return currentState; } public void back() { if (previousState != null) state(previousState); } public void state(State state) { System.out.println("PLANTUML:" + currentState + " --> " + state); if (currentState != null) currentState.exitState(this); previousState = currentState; currentState = state; if (currentState != null) currentState.enterState(this); } public boolean isStopped() { return currentState == States.STOPPED; } }