package fr.xtof54.jsgo; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.PrintWriter; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashSet; import java.util.HashSet; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.view.LayoutInflater; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import fr.xtof54.dragonGoApp.R; import fr.xtof54.jsgo.EventManager.eventType; import fr.xtof54.jsgo.GoJsActivity.guistate; public class Game { public static final int PREFER_LOCAL_SGF=0; public static final int ALWAYS_DOWNLOAD_SGF=1; public static int bandwidthMode = ALWAYS_DOWNLOAD_SGF; final static String cmdGetListOfGames = "quick_do.php?obj=game&cmd=list&view=status"; public static ArrayList<Game> games2play = new ArrayList<Game>(); public static Game gameShown = null; private int gid; private JSONArray gameinfo; List<String> sgf = null; int moveid, boardsize; // moveid comes from the sgf file public String oppMove = null; public int newMoveId=0; // newMoveId comes from the Status games sent by the server: TODO: this should be the only one ! // contains the last dead stones used to compute the score // if the player accepts this score, then these same dead stones are sent again with command AGREE String deadstInSgf=null; // contains the new stones that should be marked as dead String deadstProposal=null; private CharSequence msg = null; private int myid=-1, blackid=-1, whiteid=-1; public CharSequence getMessage() {return msg;} public void setMessage(CharSequence m) {msg=m;} public static Game createDebugGame() { Game g = new Game(null, 1); games2play.add(g); gameShown = g; return g; } @Override public String toString() { return ""+getGameID(); } /** * Called after a local game has been selected in the list of local games * * @param sgffile * @param gid */ static void savedGameChosen(final File sgffile, final int gid) { class ConfirmDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); // Get the layout inflater LayoutInflater inflater = getActivity().getLayoutInflater(); // Inflate and set the layout for the dialog // Pass null as the parent view because its going in the dialog layout View v = inflater.inflate(R.layout.error, null); // Add action buttons builder.setView(v).setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { ConfirmDialogFragment.this.getDialog().cancel(); } }) .setPositiveButton("Show", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Game g = new Game(null, gid ); g.loadSGFLocally(); g.prepareGame(); ConfirmDialogFragment.this.getDialog().cancel(); GUI.getGUI().showHome(); GoJsActivity.main.showGame(g); GoJsActivity.main.changeState(guistate.play); } }) .setNeutralButton("Remove", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { sgffile.delete(); ConfirmDialogFragment.this.getDialog().cancel(); GUI.getGUI().showHome(); } }); builder.setTitle("Choice"); TextView tv = (TextView)v.findViewById(R.id.errormsg); tv.setText("What do you want to do ?"); return builder.create(); } } ConfirmDialogFragment confirmDialog = new ConfirmDialogFragment(); confirmDialog.show(GoJsActivity.main.getSupportFragmentManager(),"SavedGameChoice"); } public static void showListSaved() { Thread forumthread = new Thread(new Runnable() { @Override public void run() { showListSaved2(); } }); forumthread.start(); } private static void showListSaved2() { final File d = GoJsActivity.main.eidogodir;//+"/mygame"+gid+".sgf"; final File[] savedGames = d.listFiles(new FilenameFilter() { @Override public boolean accept(File arg0, String arg1) { return arg1.startsWith("mygame") && arg1.endsWith(".sgf"); } }); if (savedGames==null||savedGames.length==0) { GoJsActivity.main.showMessage("no game saved"); return; } GoJsActivity.main.runOnUiThread(new Runnable() { @Override public void run() { GoJsActivity.main.setContentView(R.layout.forumcats); GoJsActivity.main.curstate=guistate.forums; final String[] c = new String[savedGames.length+1]; c[0]="remove all"; for (int i=0;i<c.length-1;i++) { String s=savedGames[i].getName().substring(6).replace(".sgf", ""); c[i+1]=s; } ArrayAdapter<String> adapter = new ArrayAdapter<String>(GoJsActivity.main, R.layout.detlistitem, c); final ListView listFrameview = (ListView)GoJsActivity.main.findViewById(R.id.forumCatsList); listFrameview.setAdapter(adapter); listFrameview.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int position, long id) { if (position==0) { for (File f: savedGames) f.delete(); System.out.println("all files deleted"); GUI.getGUI().showHome(); return; } final int n=position-1; Thread gameselthread = new Thread(new Runnable() { @Override public void run() { Game.savedGameChosen(savedGames[n],Integer.parseInt(c[n+1])); } }); gameselthread.start(); } }); } }); } public void addSgfData(String sgfdata) { if (sgf==null) sgf = new ArrayList<String>(); sgf.add(sgfdata); } public static void gotOpponentMove(int gameid, int moveid, String move) { Game g=null; for (Game gg : games2play) if (gameid==gg.gid) {g=gg; break;} if (g==null) g = new Game(null, gameid); g.loadSGFLocally(); g.prepareGame(); g.addMoveToSGF(move); g.loadSGFLocally(); g.prepareGame(); GUI.getGUI().showHome(); GoJsActivity.main.showGame(g); GoJsActivity.main.changeState(guistate.play); } /** * for now: I/System.out(11012): jsonheader 0 id I/System.out(11012): jsonheader 1 double_id I/System.out(11012): jsonheader 2 tournament_id I/System.out(11012): jsonheader 3 game_action I/System.out(11012): jsonheader 4 status I/System.out(11012): jsonheader 5 flags I/System.out(11012): jsonheader 6 score I/System.out(11012): jsonheader 7 game_type I/System.out(11012): jsonheader 8 rated I/System.out(11012): jsonheader 9 ruleset I/System.out(11012): jsonheader 10 size I/System.out(11012): jsonheader 11 komi I/System.out(11012): jsonheader 12 jigo_mode I/System.out(11012): jsonheader 13 handicap I/System.out(11012): jsonheader 14 handicap_mode I/System.out(11012): jsonheader 15 shape_id I/System.out(11012): jsonheader 16 time_started I/System.out(11012): jsonheader 17 time_lastmove I/System.out(11012): jsonheader 18 time_weekend_clock I/System.out(11012): jsonheader 19 time_mode I/System.out(11012): jsonheader 20 time_limit I/System.out(11012): jsonheader 21 my_id I/System.out(11012): jsonheader 22 move_id I/System.out(11012): jsonheader 23 move_count I/System.out(11012): jsonheader 24 move_color I/System.out(11012): jsonheader 25 move_uid I/System.out(11012): jsonheader 26 move_opp I/System.out(11012): jsonheader 27 move_last I/System.out(11012): jsonheader 28 prio I/System.out(11012): jsonheader 29 black_user.id I/System.out(11012): jsonheader 30 black_gameinfo.prisoners I/System.out(11012): jsonheader 31 black_gameinfo.remtime I/System.out(11012): jsonheader 32 black_gameinfo.rating_start I/System.out(11012): jsonheader 33 black_gameinfo.rating_start_elo I/System.out(11012): jsonheader 34 white_user.id I/System.out(11012): jsonheader 35 white_gameinfo.prisoners I/System.out(11012): jsonheader 36 white_gameinfo.remtime I/System.out(11012): jsonheader 37 white_gameinfo.rating_start I/System.out(11012): jsonheader 38 white_gameinfo.rating_start_elo * @param o */ public static void parseJSONStatusGames(JSONObject o) { if (o==null) return; try { games2play.clear(); int ngames = o.getInt("list_size"); if (ngames>0) { JSONArray headers = o.getJSONArray("list_header"); int gid_jsonidx=-1, movejsoni=-1, moveidjson=-1; int myidjson=-1, whiteidjson=-1, blackidjson=-1; for (int i=0;i<headers.length();i++) { String h = headers.getString(i); System.out.println("jsonheader "+i+" "+h); if (h.equals("id")) gid_jsonidx=i; else if (h.equals("move_last")) movejsoni=i; else if (h.equals("move_id")) moveidjson=i; else if (h.equals("my_id")) myidjson=i; else if (h.equals("white_user.id")) whiteidjson=i; else if (h.equals("black_user.id")) blackidjson=i; } JSONArray jsongames = o.getJSONArray("list_result"); int[] users = {-1,-1,-1}; for (int i=0;i<jsongames.length();i++) { JSONArray jsongame = jsongames.getJSONArray(i); int gameid = jsongame.getInt(gid_jsonidx); Game g = new Game(jsongame, gameid); if (movejsoni>=0&&moveidjson>=0) g.setOppMove(jsongame.getString(movejsoni),jsongame.getInt(moveidjson)); if (myidjson>=0) users[0]=jsongame.getInt(myidjson); if (blackidjson>=0) users[1]=jsongame.getInt(blackidjson); if (whiteidjson>=0) users[2]=jsongame.getInt(whiteidjson); g.setUsers(users); games2play.add(g); } System.out.println("games in the list "+games2play.size()); } } catch (JSONException e) { e.printStackTrace(); } } private static int[] getKnownGames() { HashSet<Integer> games = new HashSet<Integer>(); for (Game g : games2play) games.add(g.getGameID()); final File d = GoJsActivity.main.eidogodir;//+"/mygame"+gid+".sgf"; final File[] savedGames = d.listFiles(new FilenameFilter() { @Override public boolean accept(File arg0, String arg1) { return arg1.startsWith("mygame") && arg1.endsWith(".sgf"); } }); if (savedGames!=null) { for (File f: savedGames) { int i=Integer.parseInt(f.getName().substring(6, f.getName().length()-4)); games.add(i); } } int[] gs = new int[games.size()]; int j=0; for (int i:games) gs[j++]=i; return gs; } public static void loadStatusGames(final ServerConnection server) { Thread push = new Thread(new Runnable() { @Override public void run() { final EventManager em = EventManager.getEventManager(); if (GoJsActivity.main.getGamesFromDGS) { System.out.println("loadstatusgame DGS "); EventManager.EventListener f = new EventManager.EventListener() { @Override public synchronized void reactToEvent() { JSONObject o = server.o; parseJSONStatusGames(o); // also connects now to the client server to give it time to connect correctly // if (games2play.size() > 0) WSclient.init(games2play.get(0).myid); System.out.println("end of loadstatusgame, unregistering listener " + games2play.size()); em.unregisterListener(eventType.downloadListEnd, this); } @Override public String getName() { return "loadStatusGame"; } }; em.registerListener(eventType.downloadListEnd, f); server.sendCmdToServer(cmdGetListOfGames, eventType.downloadListStarted, eventType.downloadListEnd); } if (GoJsActivity.main.getGamesFromOGS) { System.out.println("loadstatusgame OGS "); System.out.println("OGS login:"); OGSConnection.login(); } em.sendEvent(eventType.downloadListGamesEnd); } }); push.start(); } public static List<Game> getGames() {return games2play;} Game(JSONArray gameObject, int gameid) { gid=gameid; gameinfo = gameObject; } public String getGameStatus() { try { if (gameinfo==null||gameinfo.length()<5) return ""; return gameinfo.getString(4); } catch (JSONException e) { e.printStackTrace(); return null; } } private void setUsers(int[] uids) { myid=uids[0]; blackid=uids[1]; whiteid=uids[2]; } public int getGameID() {return gid;} public void showGame() { System.out.println("writing game sgf to example.html"); if (sgf==null) { System.out.println("ERROR impossible to show game "+gid); return; } try { PrintWriter fout = new PrintWriter(new FileWriter(GoJsActivity.main.eidogodir+"/example.html")); for (String s : exampleFileHtmlHeader) fout.println(s); for (int i=0;i<sgf.size();i++) fout.println(sgf.get(i)); for (String s : htmlend) fout.println(s); fout.close(); } catch (IOException e) { e.printStackTrace(); } gameShown=this; System.out.println("example.html up to date"); } /** * Warning: once a first player has marked stone and send his agreement to the server, the dead stones are stored in the server * and the new game status is SCORE2: this should be the correct way to detect this stage. * And we cannot any more send new dead stones to know the score (?) */ private void checkIfDeadStonesMarked() { // start from the end, because there may be several sets of dead stones marked for (int i=sgf.size()-1;i>=0;i--) { String s=sgf.get(i); int j=s.indexOf("MA["); if (j>=0) { // there are dead stones marked ! deadstInSgf=""; j+=3; while (j<s.length()) { deadstInSgf+=s.substring(j,j+2); if (j+3>=s.length()||s.charAt(j+3)!='[') break; j+=4; } break; } } } // should never be used ? public void removeDeadStonesFromSgf() { deadstInSgf=null; int debdeadstones=-1, enddeadstones=-1, deadidx=-1; for (int i=0;i<sgf.size();i++) { String s=sgf.get(i); int j=s.indexOf("MA["); if (j>=0) { // there are dead stones marked ! debdeadstones=j; deadidx=i; j+=3; while (j<s.length()) { if (j+3>=s.length()||s.charAt(j+3)!='[') break; j+=4; } enddeadstones=j+4; break; } } if (debdeadstones>=0) { String s = sgf.get(deadidx); s=s.substring(0, debdeadstones); sgf.set(deadidx, s); } } // return false = isn't finished = keep the game ! public boolean finishedWithThisGame() { System.out.println("ogsgamelist "+getGameID()+" "+games2play); if (getGameID()<0) { // OGS game: check if sendMove has succeeded ! if (!OGSConnection.sendMoveIsSuccess) return false; } else { // DGS Game: also check JSONObject o = GoJsActivity.main.server.o; if (o != null) { String err; try { err = o.getString("error"); if (err != null && err.length() > 0) { // error: don't switch game return false; } } catch (JSONException e) { e.printStackTrace(); } } } // bizarre, le remove ne marche pas toujours... ? ArrayList<Game> newl = new ArrayList<Game>(); for (int i=0;i<games2play.size();i++) if (games2play.get(i).getGameID()!=getGameID()) newl.add(games2play.get(i)); games2play=newl; System.out.println("ogsgamelist2 " + games2play); gameShown=null; return true; } public boolean isInScoring() { if (getGameStatus().startsWith("SCORE")) { return true; } return false; } public boolean isTwoPasses() { if (sgf==null) return false; String lastb="12", lastw="32"; for (int i=0;i<sgf.size();i++) { String s=sgf.get(i); { int z=s.lastIndexOf("B["); int zz=s.indexOf(']',z); if (z>=0) lastb=s.substring(z+2, zz); } { int z=s.lastIndexOf("W["); int zz=s.indexOf(']',z); if (z>=0) lastw=s.substring(z+2, zz); } } // detect if in scoring phase System.out.println("debuglastmoves --"+lastw+"--"+lastb); if ((lastb.equals("")||lastb.equals("tt")) && ((lastw.equals("")||lastw.equals("tt")))) { return true; } else return false; } private void saveSGFLocally() { try { PrintWriter fout = new PrintWriter(new FileWriter(GoJsActivity.main.eidogodir+"/mygame"+gid+".sgf")); for (int i=0;i<sgf.size();i++) fout.println(sgf.get(i)); fout.close(); } catch (IOException e) { e.printStackTrace(); } } public int countMovesInSgf() { int n=0; for (int i=0;i<sgf.size();i++) { if (sgf.get(i).length()>0&&sgf.get(i).charAt(0)==';') n++; } return n; } public boolean loadSGFLocally(String fname) { File f0 = new File(fname); if (!f0.exists()) return false; try { BufferedReader f = new BufferedReader(new FileReader(f0)); sgf = new ArrayList<String>(); for (;;) { String s=f.readLine(); if (s==null) break; sgf.add(s); } f.close(); } catch (IOException e) { e.printStackTrace(); return false; } return true; } private boolean loadSGFLocally() { final String fname = GoJsActivity.main.eidogodir+"/mygame"+gid+".sgf"; return loadSGFLocally(fname); } void addResignToSGF() { // TODO } // it is always called just after addmove or addresign void addMessageToSGF(String msg) { sgf.add(sgf.size()-1, "C["+msg.trim()+"]"); saveSGFLocally(); } void addMoveToSGF(String move) { char oppColor; if (sgf.size()<2 || sgf.get(sgf.size()-2).length()<2) { oppColor='W'; } else oppColor = sgf.get(sgf.size()-2).charAt(1); char myColor = oppColor=='W'?'B':'W'; sgf.add(sgf.size()-1, ";"+myColor+"["+move+"]"); saveSGFLocally(); } void setOppMove(String move, int mid) { oppMove=move; newMoveId=mid; } void prepareGame() { // look for move_id and size for (String s: sgf) { int i=s.indexOf("XM["); if (i>=0) { int j=s.indexOf(']',i+3); moveid = Integer.parseInt(s.substring(i+3, j)); } i=s.indexOf("SZ["); if (i>=0) { int j=s.indexOf(']',i+3); boardsize = Integer.parseInt(s.substring(i+3, j)); } } checkIfDeadStonesMarked(); System.out.println("sgf: "+sgf); System.out.println("moveid "+moveid); System.out.println("deadstones in SGF: "+deadstInSgf); final EventManager em = EventManager.getEventManager(); em.sendEvent(eventType.GameOK); } // est-ce qu'il faut garder le meme httpclient qu'avant pour pouvoir beneficier du proxy ? ==> OUI public void downloadGame(final ServerConnection server) { final EventManager em = EventManager.getEventManager(); if (bandwidthMode==PREFER_LOCAL_SGF&&loadSGFLocally()) { if (oppMove!=null) { // This game has already been created, for instance by downloading statusGame from DGS /* * It can happen that the user plays a move, so the local sgf is updated (but not the moveid !), * but the move is not sent correctly to the server. Then, next time status games are downloaded, * the newMoveId will actually be late by 2 moves, as compared to the *actual* nb of moves in the sgf. * Then, we must warn the user, and propose him to resend his move or rethink about it. * * Also, the user may play some time on another computer. In all these cases, we have to resync. */ int nActualMovesInSgf = countMovesInSgf(); if (newMoveId==nActualMovesInSgf-2) { em.sendEvent(eventType.downloadGameStarted); // the user last move has not been received by the DGS server GoJsActivity.main.showMessage("last move not received by server: you may resend it"); em.sendEvent(eventType.downloadGameEnd); } else if (newMoveId==nActualMovesInSgf) { em.sendEvent(eventType.downloadGameStarted); // we got a new move from the server addMoveToSGF(oppMove); // and save GoJsActivity.main.showMessage("detected a new move from server"); em.sendEvent(eventType.downloadGameEnd); } else { GoJsActivity.main.showMessage("Server not sync - reloading"); System.out.println("ERROR: strange nmoves "+getGameID()+" "+nActualMovesInSgf+" "+newMoveId+ " re-downloading..."); downloadSGF(server); return; } } else { // the user is just looking at a local game em.sendEvent(eventType.downloadGameStarted); em.sendEvent(eventType.downloadGameEnd); } prepareGame(); GoJsActivity.main.showMessage("game loaded locally"); return; } downloadSGF(server); } public void downloadSGF(final ServerConnection server) { final EventManager em = EventManager.getEventManager(); EventManager.EventListener f = new EventManager.EventListener() { @Override public synchronized void reactToEvent() { em.unregisterListener(eventType.downloadGameEnd, this); sgf = new ArrayList<String>(); for (String s : server.sgf) sgf.add(""+s); saveSGFLocally(); prepareGame(); } @Override public String getName() {return "downloadGame";} }; em.registerListener(eventType.downloadGameEnd, f); server.downloadSgf(gid, true); } public int getBoardSize() {return boardsize;} // GoJsActivity.main.runInWaitingThread(new Runnable() { // @Override // public void run() { // HttpGet httpget = new HttpGet(GoJsActivity.main.server+"sgf.php?gid="+gid+"&owned_comments=1&quick_mode=1"); // try { // HttpParams httpparms = new BasicHttpParams(); // HttpConnectionParams.setConnectionTimeout(httpparms, 6000); // HttpConnectionParams.setSoTimeout(httpparms, 6000); // HttpClient httpclient = new DefaultHttpClient(httpparms); // HttpResponse response = httpclient.execute(httpget); // Header[] heds = response.getAllHeaders(); // for (Header s : heds) // System.out.println("[HEADER] "+s); // HttpEntity entity = response.getEntity(); // if (entity != null) { // InputStream instream = entity.getContent(); // BufferedReader fin = new BufferedReader(new InputStreamReader(instream, Charset.forName("UTF-8"))); // for (;;) { // String s = fin.readLine(); // if (s==null) break; // s=s.trim(); // if (s.length()>0&&s.charAt(0)!='[') { // // look for move_id // int i=s.indexOf("XM["); // if (i>=0) { // int j=s.indexOf(']',i+3); // moveid = Integer.parseInt(s.substring(i+3, j)); // } // sgf.add(s); // } // System.out.println("SGFdownload "+s); // } // fin.close(); // } // httpclient.getConnectionManager().shutdown(); // } catch (Exception e) { // GoJsActivity.main.showMsg(GoJsActivity.main.netErrMsg); // e.printStackTrace(); // } // } // }); final String[] exampleFileHtmlHeader = { "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"", " \"http://www.w3.org/TR/html4/loose.dtd\">", "<html>", "<head>", " <title>Xtof54 GoJs</title>", "", " <!--", " Optional config - defaults given", " -->", " <script type=\"text/javascript\">", " eidogoConfig = {", " theme: \"compact\",", " mode: \"play\",", " showComments: true,", " showPlayerInfo: false,", " showGameInfo: false,", " showTools: false,", " showOptions: false,", " markCurrent: true,", " markVariations: true,", " markNext: false,", " problemMode: false,", " enableShortcuts: false", " };", " </script>", " ", " <!--", " Optional international support (see player/i18n/ folder)", " -->", "<script type=\"text/javascript\" src=\"player/js/lang.js\"></script>", "<script type=\"text/javascript\" src=\"player/js/eidogo.js\"></script>", "<script type=\"text/javascript\" src=\"player/js/util.js\"></script>", "<script type=\"text/javascript\" src=\"player/i18n/en.js\"></script>", "<script type=\"text/javascript\" src=\"player/js/gametree.js\"></script>", "<script type=\"text/javascript\" src=\"player/js/sgf.js\"></script>", "<script type=\"text/javascript\" src=\"player/js/board.js\"></script>", "<script type=\"text/javascript\" src=\"player/js/rules.js\"></script>", "<script type=\"text/javascript\" src=\"player/js/player.js\"></script>", "<script type=\"text/javascript\" src=\"player/js/init.js\"></script>", "</head>", "<body>", " <div class=\"eidogo-player-auto\">", }; final String[] htmlend = { " </div>", "</body>", "</html>", }; public void acceptScore(final ServerConnection server) { System.out.println("acceptScore deadstones "+deadstProposal); String cmd = "quick_do.php?obj=game&cmd=score&gid="+getGameID()+"&toggle=uniq&move="+deadstProposal+"&move_id="+moveid; server.sendCmdToServer(cmd,eventType.moveSentStart,eventType.moveSentEnd); } /** * In SCORE mode, we can send directly the stones marked by the user, * but in SCORE2 mode, we have to toggle the stones marked with the stones on the server ! * * * @param deadstones are the stones marked with X on the goban by the user * @param server */ public void sendDeadstonesToServer(String deadstones, final ServerConnection server, boolean toggle) { System.out.println("deadstones on the goban"+deadstones); if (getGameStatus().equals("SCORE2")) { if (!toggle) { deadstProposal = ""+deadstones; } else { // compute the dead stones proposal deadstProposal=""; ArrayList<String> stonesRemovedFromGoban = new ArrayList<String>(); for (int j=0;j<deadstInSgf.length();j+=2) { String sgfMarkedStone = deadstInSgf.substring(j,j+2); stonesRemovedFromGoban.add(sgfMarkedStone); } for (int i=0;i<deadstones.length();i+=2) { String gobanMarkedStone = deadstones.substring(i,i+2); // is this stone already marked in the SGF ? boolean isStoneMarkedInSgf = false; int j; for (j=0;j<stonesRemovedFromGoban.size();j++) { String s=stonesRemovedFromGoban.get(j); if (s.equals(gobanMarkedStone)) { isStoneMarkedInSgf=true; break; } } if (isStoneMarkedInSgf) { // we don't add it to the proposal, because it's already in there (?) stonesRemovedFromGoban.remove(j); } else { deadstProposal+=gobanMarkedStone; } } for (int j=0;j<stonesRemovedFromGoban.size();j++) { // we have to toggle off the stones that are not marked anymore deadstProposal+=stonesRemovedFromGoban.get(j); } } } else if (getGameStatus().equals("SCORE")) { deadstProposal = ""+deadstones; } else { System.out.println("ERROR senddeadstones without being in SCORE mode !"); return; } System.out.println("deadstones proposal "+deadstProposal); String cmd = "quick_do.php?obj=game&cmd=status_score&gid="+getGameID()+"&toggle=uniq&move="+deadstProposal; server.sendCmdToServer(cmd,eventType.moveSentStart,eventType.moveSentEnd); } private int getOppID() { if (myid==whiteid) return blackid; else return whiteid; } // this function is called by the "weblistener" that captures the last move from the embedded javascript public void sendMove2server(String move, final ServerConnection server) { if (gid>=0&&server==null) { if (!GoJsActivity.main.initServer()) return; sendMove2server(move, GoJsActivity.main.server); return; } if (move.toLowerCase().startsWith("tt")) move="pass"; System.out.println("move "+move); final String finmove = move; // ask for confirmation before sending class ConfirmDialogFragment extends DialogFragment { String cmdSentBeforeNetErr; eventType eventTobesent; GoJsActivity main; public void setArguments(String s, eventType e, GoJsActivity m) { cmdSentBeforeNetErr = s; eventTobesent = e; main=m; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); // Get the layout inflater LayoutInflater inflater = getActivity().getLayoutInflater(); // Inflate and set the layout for the dialog // Pass null as the parent view because its going in the dialog layout View v = inflater.inflate(R.layout.error, null); // Add action buttons builder.setView(v).setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { ConfirmDialogFragment.this.getDialog().cancel(); } }) .setPositiveButton("OK, send !", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { addMoveToSGF(finmove); if (gid>=0) { // this is a DGS game String cmd = "quick_do.php?obj=game&cmd=move&gid=" + getGameID() + "&move_id=" + newMoveId + "&move=" + finmove; if (msg != null) { addMessageToSGF(msg.toString()); cmd += "&msg=" + URLEncoder.encode(msg.toString()); } // TODO: check that server exists // this first command sends the move to the DGS server server.sendCmdToServer(cmd, eventType.moveSentStart, eventType.moveSentEnd); // this second command sends the move to the push server for real-time playing // WSclient.sendMove(getGameID(), newMoveId, finmove, getOppID()); } else { // OGS move final EventManager em = EventManager.getEventManager(); em.sendEvent(eventType.moveSentStart); OGSConnection.sendMove(-gid, finmove); em.sendEvent(eventType.moveSentEnd); } ConfirmDialogFragment.this.getDialog().cancel(); } }); builder.setTitle("Confirmation"); TextView tv = (TextView)v.findViewById(R.id.errormsg); // transform internal move rep to user-type moves: String usermove = finmove; if (finmove.length()==2) { char col=Character.toUpperCase(finmove.charAt(0)); if (Character.toLowerCase(finmove.charAt(0))>='i') { col=(char)((int)col+1); } int row = boardsize-((int)Character.toUpperCase(finmove.charAt(1))-(int)'A'); usermove=""+col; usermove+=row; } tv.setText("Confirm move "+usermove+" ?"); return builder.create(); } } ConfirmDialogFragment confirmDialog = new ConfirmDialogFragment(); confirmDialog.show(GoJsActivity.main.getSupportFragmentManager(),"confirmBeforeSend"); } }