mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2024-11-23 11:31:33 +01:00
Implement auto-save of old game when starting a new game
The 20 most recently auto-saved games are kept in the file DroidFish/pgn/.autosave.pgn. Overwriting an existing game when saving a new game also auto-saves the old game.
This commit is contained in:
parent
ce544c6be8
commit
683a238bff
|
@ -588,7 +588,7 @@ public class DroidFish extends Activity
|
|||
ctrl.startGame();
|
||||
if (intentPgnOrFen != null) {
|
||||
try {
|
||||
ctrl.setFENOrPGN(intentPgnOrFen);
|
||||
ctrl.setFENOrPGN(intentPgnOrFen, true);
|
||||
setBoardFlip(true);
|
||||
} catch (ChessParseError e) {
|
||||
// If FEN corresponds to illegal chess position, go into edit board mode.
|
||||
|
@ -1019,6 +1019,8 @@ public class DroidFish extends Activity
|
|||
});
|
||||
}
|
||||
|
||||
private static final int serializeVersion = 4;
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
@ -1026,7 +1028,7 @@ public class DroidFish extends Activity
|
|||
byte[] data = ctrl.toByteArray();
|
||||
byte[] token = data == null ? null : cache.storeBytes(data);
|
||||
outState.putByteArray("gameStateT", token);
|
||||
outState.putInt("gameStateVersion", 3);
|
||||
outState.putInt("gameStateVersion", serializeVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1049,7 +1051,7 @@ public class DroidFish extends Activity
|
|||
Editor editor = settings.edit();
|
||||
String dataStr = byteArrToString(data);
|
||||
editor.putString("gameState", dataStr);
|
||||
editor.putInt("gameStateVersion", 3);
|
||||
editor.putInt("gameStateVersion", serializeVersion);
|
||||
editor.apply();
|
||||
}
|
||||
lastVisibleMillis = System.currentTimeMillis();
|
||||
|
@ -1568,16 +1570,17 @@ public class DroidFish extends Activity
|
|||
}
|
||||
}
|
||||
|
||||
static private final int RESULT_EDITBOARD = 0;
|
||||
static private final int RESULT_SETTINGS = 1;
|
||||
static private final int RESULT_LOAD_PGN = 2;
|
||||
static private final int RESULT_LOAD_FEN = 3;
|
||||
static private final int RESULT_SELECT_SCID = 4;
|
||||
static private final int RESULT_OI_PGN_SAVE = 5;
|
||||
static private final int RESULT_OI_PGN_LOAD = 6;
|
||||
static private final int RESULT_OI_FEN_LOAD = 7;
|
||||
static private final int RESULT_GET_FEN = 8;
|
||||
static private final int RESULT_EDITOPTIONS = 9;
|
||||
static private final int RESULT_EDITBOARD = 0;
|
||||
static private final int RESULT_SETTINGS = 1;
|
||||
static private final int RESULT_LOAD_PGN = 2;
|
||||
static private final int RESULT_LOAD_FEN = 3;
|
||||
static private final int RESULT_SAVE_PGN = 4;
|
||||
static private final int RESULT_SELECT_SCID = 5;
|
||||
static private final int RESULT_OI_PGN_SAVE = 6;
|
||||
static private final int RESULT_OI_PGN_LOAD = 7;
|
||||
static private final int RESULT_OI_FEN_LOAD = 8;
|
||||
static private final int RESULT_GET_FEN = 9;
|
||||
static private final int RESULT_EDITOPTIONS = 10;
|
||||
|
||||
private void startEditBoard(String fen) {
|
||||
Intent i = new Intent(DroidFish.this, EditBoard.class);
|
||||
|
@ -1595,7 +1598,7 @@ public class DroidFish extends Activity
|
|||
if (resultCode == RESULT_OK) {
|
||||
try {
|
||||
String fen = data.getAction();
|
||||
ctrl.setFENOrPGN(fen);
|
||||
ctrl.setFENOrPGN(fen, true);
|
||||
setBoardFlip(false);
|
||||
} catch (ChessParseError ignore) {
|
||||
}
|
||||
|
@ -1609,13 +1612,19 @@ public class DroidFish extends Activity
|
|||
int modeNr = ctrl.getGameMode().getModeNr();
|
||||
if ((modeNr != GameMode.ANALYSIS) && (modeNr != GameMode.EDIT_GAME))
|
||||
newGameMode(GameMode.EDIT_GAME);
|
||||
ctrl.setFENOrPGN(pgn);
|
||||
ctrl.setFENOrPGN(pgn, false);
|
||||
setBoardFlip(true);
|
||||
} catch (ChessParseError e) {
|
||||
DroidFishApp.toast(getParseErrString(e), Toast.LENGTH_SHORT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RESULT_SAVE_PGN:
|
||||
if (resultCode == RESULT_OK) {
|
||||
long hash = data.getLongExtra("org.petero.droidfish.treeHash", -1);
|
||||
ctrl.setLastSaveHash(hash);
|
||||
}
|
||||
break;
|
||||
case RESULT_SELECT_SCID:
|
||||
if (resultCode == RESULT_OK) {
|
||||
String pathName = data.getAction();
|
||||
|
@ -1662,13 +1671,13 @@ public class DroidFish extends Activity
|
|||
String pathName = getFilePathFromUri(data.getData());
|
||||
loadFENFromFile(pathName);
|
||||
}
|
||||
setFenHelper(fen);
|
||||
setFenHelper(fen, true);
|
||||
}
|
||||
break;
|
||||
case RESULT_LOAD_FEN:
|
||||
if (resultCode == RESULT_OK) {
|
||||
String fen = data.getAction();
|
||||
setFenHelper(fen);
|
||||
setFenHelper(fen, false);
|
||||
}
|
||||
break;
|
||||
case RESULT_EDITOPTIONS:
|
||||
|
@ -2090,7 +2099,6 @@ public class DroidFish extends Activity
|
|||
editor.apply();
|
||||
gameMode = new GameMode(gameModeType);
|
||||
}
|
||||
// savePGNToFile(".autosave.pgn", true);
|
||||
TimeControlData tcData = new TimeControlData();
|
||||
tcData.setTimeControl(timeControl, movesPerSession, timeIncrement);
|
||||
speech.flushQueue();
|
||||
|
@ -2161,10 +2169,10 @@ public class DroidFish extends Activity
|
|||
writer.close();
|
||||
loadPGNFromFile(fn);
|
||||
} catch (IOException ex) {
|
||||
ctrl.setFENOrPGN(fenPgnData);
|
||||
ctrl.setFENOrPGN(fenPgnData, true);
|
||||
}
|
||||
} else {
|
||||
ctrl.setFENOrPGN(fenPgnData);
|
||||
ctrl.setFENOrPGN(fenPgnData, true);
|
||||
}
|
||||
setBoardFlip(true);
|
||||
} catch (ChessParseError e) {
|
||||
|
@ -3476,8 +3484,33 @@ public class DroidFish extends Activity
|
|||
i.setAction("org.petero.droidfish.saveFile");
|
||||
i.putExtra("org.petero.droidfish.pathname", pathName);
|
||||
i.putExtra("org.petero.droidfish.pgn", pgnToken);
|
||||
i.putExtra("org.petero.droidfish.silent", false);
|
||||
startActivity(i);
|
||||
setEditPGNBackup(i, pathName);
|
||||
startActivityForResult(i, RESULT_SAVE_PGN);
|
||||
}
|
||||
|
||||
/** Set a Boolean value in the Intent to decide if backups should be made
|
||||
* when games in a PGN file are overwritten or deleted. */
|
||||
private void setEditPGNBackup(Intent i, String pathName) {
|
||||
boolean backup = storageAvailable() && !pathName.equals(getAutoSaveFile());
|
||||
i.putExtra("org.petero.droidfish.backup", backup);
|
||||
}
|
||||
|
||||
/** Get the full path to the auto-save file. */
|
||||
private static String getAutoSaveFile() {
|
||||
String sep = File.separator;
|
||||
return Environment.getExternalStorageDirectory() + sep + pgnDir + sep + ".autosave.pgn";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void autoSaveGameIfAllowed(String pgn) {
|
||||
if (storageAvailable())
|
||||
autoSaveGame(pgn);
|
||||
}
|
||||
|
||||
/** Save a copy of the pgn data in the .autosave.pgn file. */
|
||||
public static void autoSaveGame(String pgn) {
|
||||
PGNFile pgnFile = new PGNFile(getAutoSaveFile());
|
||||
pgnFile.autoSave(pgn);
|
||||
}
|
||||
|
||||
/** Load a PGN game from a file. */
|
||||
|
@ -3489,6 +3522,7 @@ public class DroidFish extends Activity
|
|||
Intent i = new Intent(DroidFish.this, EditPGNLoad.class);
|
||||
i.setAction("org.petero.droidfish.loadFile");
|
||||
i.putExtra("org.petero.droidfish.pathname", pathName);
|
||||
setEditPGNBackup(i, pathName);
|
||||
startActivityForResult(i, RESULT_LOAD_PGN);
|
||||
}
|
||||
|
||||
|
@ -3506,11 +3540,11 @@ public class DroidFish extends Activity
|
|||
startActivityForResult(i, RESULT_LOAD_FEN);
|
||||
}
|
||||
|
||||
private void setFenHelper(String fen) {
|
||||
private void setFenHelper(String fen, boolean setModified) {
|
||||
if (fen == null)
|
||||
return;
|
||||
try {
|
||||
ctrl.setFENOrPGN(fen);
|
||||
ctrl.setFENOrPGN(fen, setModified);
|
||||
} catch (ChessParseError e) {
|
||||
// If FEN corresponds to illegal chess position, go into edit board mode.
|
||||
try {
|
||||
|
|
|
@ -108,4 +108,7 @@ public interface GUIInterface {
|
|||
|
||||
/** Return true if only main-line moves are to be kept. */
|
||||
boolean discardVariations();
|
||||
|
||||
/** Save the current game to the auto-save file, if storage permission has been granted. */
|
||||
void autoSaveGameIfAllowed(String pgn);
|
||||
}
|
||||
|
|
|
@ -128,4 +128,26 @@ public final class Util {
|
|||
((MoveListView) v).setTextColor(fg);
|
||||
}
|
||||
}
|
||||
|
||||
/** Return a hash value for a string, with better quality than String.hashCode(). */
|
||||
public static long stringHash(String s) {
|
||||
int n = s.length();
|
||||
long h = n;
|
||||
for (int i = 0; i < n; i += 4) {
|
||||
long tmp = s.charAt(i) & 0xffff;
|
||||
try {
|
||||
tmp = (tmp << 16) | (s.charAt(i+1) & 0xffff);
|
||||
tmp = (tmp << 16) | (s.charAt(i+2) & 0xffff);
|
||||
tmp = (tmp << 16) | (s.charAt(i+3) & 0xffff);
|
||||
} catch (IndexOutOfBoundsException ignore) {}
|
||||
|
||||
h += tmp;
|
||||
|
||||
h *= 0x7CF9ADC6FE4A7653L;
|
||||
h ^= h >>> 37;
|
||||
h *= 0xC25D3F49433E7607L;
|
||||
h ^= h >>> 43;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import android.os.Bundle;
|
|||
import android.preference.PreferenceManager;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Pair;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -45,6 +44,7 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import org.petero.droidfish.ColorTheme;
|
||||
import org.petero.droidfish.DroidFish;
|
||||
import org.petero.droidfish.DroidFishApp;
|
||||
import org.petero.droidfish.ObjectCache;
|
||||
import org.petero.droidfish.R;
|
||||
|
@ -74,6 +74,7 @@ public abstract class EditPGN extends AppCompatActivity {
|
|||
private String lastFileName = "";
|
||||
private long lastModTime = -1;
|
||||
private boolean useRegExp = false;
|
||||
private boolean backup = false; // If true, backup PGN games before overwriting
|
||||
|
||||
private Thread workThread = null;
|
||||
private boolean canceled = false;
|
||||
|
@ -109,6 +110,7 @@ public abstract class EditPGN extends AppCompatActivity {
|
|||
Intent i = getIntent();
|
||||
String action = i.getAction();
|
||||
String fileName = i.getStringExtra("org.petero.droidfish.pathname");
|
||||
backup = i.getBooleanExtra("org.petero.droidfish.backup", false);
|
||||
canceled = false;
|
||||
if ("org.petero.droidfish.loadFile".equals(action)) {
|
||||
pgnFile = new PGNFile(fileName);
|
||||
|
@ -167,36 +169,37 @@ public abstract class EditPGN extends AppCompatActivity {
|
|||
loadGame = false;
|
||||
String token = i.getStringExtra("org.petero.droidfish.pgn");
|
||||
pgnToSave = (new ObjectCache()).retrieveString(token);
|
||||
boolean silent = i.getBooleanExtra("org.petero.droidfish.silent", false);
|
||||
if (silent) { // Silently append to file
|
||||
PGNFile pgnFile2 = new PGNFile(fileName);
|
||||
pgnFile2.appendPGN(pgnToSave);
|
||||
} else {
|
||||
pgnFile = new PGNFile(fileName);
|
||||
showDialog(PROGRESS_DIALOG);
|
||||
workThread = new Thread(() -> {
|
||||
if (!readFile())
|
||||
return;
|
||||
runOnUiThread(() -> {
|
||||
if (canceled) {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
} else if (gamesInFile.isEmpty()) {
|
||||
pgnFile.appendPGN(pgnToSave);
|
||||
finish();
|
||||
} else {
|
||||
showList();
|
||||
}
|
||||
});
|
||||
pgnFile = new PGNFile(fileName);
|
||||
showDialog(PROGRESS_DIALOG);
|
||||
workThread = new Thread(() -> {
|
||||
if (!readFile())
|
||||
return;
|
||||
runOnUiThread(() -> {
|
||||
if (canceled) {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
} else if (gamesInFile.isEmpty()) {
|
||||
pgnFile.appendPGN(pgnToSave, false);
|
||||
saveFileFinished();
|
||||
} else {
|
||||
showList();
|
||||
}
|
||||
});
|
||||
workThread.start();
|
||||
}
|
||||
});
|
||||
workThread.start();
|
||||
} else { // Unsupported action
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveFileFinished() {
|
||||
Intent i = new Intent();
|
||||
i.putExtra("org.petero.droidfish.treeHash", Util.stringHash(pgnToSave));
|
||||
setResult(RESULT_OK, i);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
super.attachBaseContext(DroidFishApp.setLanguage(newBase, false));
|
||||
|
@ -403,8 +406,9 @@ public abstract class EditPGN extends AppCompatActivity {
|
|||
finish();
|
||||
return;
|
||||
}
|
||||
pgnFile.replacePGN(pgnToSave, giToReplace);
|
||||
finish();
|
||||
doBackup(giToReplace);
|
||||
pgnFile.replacePGN(pgnToSave, giToReplace, false);
|
||||
saveFileFinished();
|
||||
});
|
||||
return builder.create();
|
||||
}
|
||||
|
@ -475,6 +479,7 @@ public abstract class EditPGN extends AppCompatActivity {
|
|||
}
|
||||
|
||||
private void deleteGame(GameInfo gi) {
|
||||
doBackup(gi);
|
||||
if (pgnFile.deleteGame(gi, gamesInFile)) {
|
||||
createAdapter();
|
||||
String s = binding.selectGameFilter.getText().toString();
|
||||
|
@ -485,6 +490,15 @@ public abstract class EditPGN extends AppCompatActivity {
|
|||
}
|
||||
}
|
||||
|
||||
private void doBackup(GameInfo gi) {
|
||||
if (!backup)
|
||||
return;
|
||||
String pgn = pgnFile.readOneGame(gi);
|
||||
if (pgn == null || pgn.isEmpty())
|
||||
return;
|
||||
DroidFish.autoSaveGame(pgn);
|
||||
}
|
||||
|
||||
private void createAdapter() {
|
||||
aa = new GameAdapter<GameInfo>(this, R.layout.select_game_list_item, gamesInFile) {
|
||||
@Override
|
||||
|
|
|
@ -121,6 +121,7 @@ public class PGNFile {
|
|||
public void reset() {
|
||||
len = 0;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return new String(buf, 0, len);
|
||||
}
|
||||
|
@ -421,11 +422,37 @@ public class PGNFile {
|
|||
}
|
||||
|
||||
/** Append PGN to the end of this PGN file. */
|
||||
public void appendPGN(String pgn) {
|
||||
public void appendPGN(String pgn, boolean silent) {
|
||||
mkDirs();
|
||||
try (FileWriter fw = new FileWriter(fileName, true)) {
|
||||
fw.write(pgn);
|
||||
DroidFishApp.toast(R.string.game_saved, Toast.LENGTH_SHORT);
|
||||
if (!silent)
|
||||
DroidFishApp.toast(R.string.game_saved, Toast.LENGTH_SHORT);
|
||||
} catch (IOException e) {
|
||||
DroidFishApp.toast(R.string.failed_to_save_game, Toast.LENGTH_SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
/** Save a PGN game first in the file and remove games at the end of the file
|
||||
* to enforce a maximum number of games in the auto-save file. */
|
||||
public void autoSave(String pgn) {
|
||||
final int maxAutoSaveGames = 20;
|
||||
try {
|
||||
if (!fileName.exists()) {
|
||||
appendPGN(pgn, true);
|
||||
} else {
|
||||
ArrayList<GameInfo> gamesInFile = getGameInfo(null, null);
|
||||
for (int i = gamesInFile.size() - 1; i >= 0; i--) {
|
||||
GameInfo gi = gamesInFile.get(i);
|
||||
String oldGame = readOneGame(gi);
|
||||
if (pgn.equals(oldGame))
|
||||
deleteGame(gi, gamesInFile);
|
||||
}
|
||||
while (gamesInFile.size() > maxAutoSaveGames - 1)
|
||||
deleteGame(gamesInFile.get(gamesInFile.size() - 1), gamesInFile);
|
||||
GameInfo gi = new GameInfo().setNull(0);
|
||||
replacePGN(pgn, gi, true);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
DroidFishApp.toast(R.string.failed_to_save_game, Toast.LENGTH_SHORT);
|
||||
}
|
||||
|
@ -463,7 +490,7 @@ public class PGNFile {
|
|||
return false;
|
||||
}
|
||||
|
||||
void replacePGN(String pgnToSave, GameInfo gi) {
|
||||
void replacePGN(String pgnToSave, GameInfo gi, boolean silent) {
|
||||
try {
|
||||
File tmpFile = new File(fileName + ".tmp_delete");
|
||||
try (RandomAccessFile fileReader = new RandomAccessFile(fileName, "r");
|
||||
|
@ -475,7 +502,8 @@ public class PGNFile {
|
|||
}
|
||||
if (!tmpFile.renameTo(fileName))
|
||||
throw new IOException();
|
||||
DroidFishApp.toast(R.string.game_saved, Toast.LENGTH_SHORT);
|
||||
if (!silent)
|
||||
DroidFishApp.toast(R.string.game_saved, Toast.LENGTH_SHORT);
|
||||
} catch (IOException e) {
|
||||
DroidFishApp.toast(R.string.failed_to_save_game, Toast.LENGTH_SHORT);
|
||||
}
|
||||
|
@ -494,6 +522,7 @@ public class PGNFile {
|
|||
}
|
||||
}
|
||||
|
||||
/** Delete the file. */
|
||||
boolean delete() {
|
||||
return fileName.delete();
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ import org.petero.droidfish.gamelogic.GameTree.Node;
|
|||
/** The glue between the chess engine and the GUI. */
|
||||
public class DroidChessController {
|
||||
private DroidComputerPlayer computerPlayer = null;
|
||||
private PgnToken.PgnTokenReceiver gameTextListener = null;
|
||||
private PgnToken.PgnTokenReceiver gameTextListener;
|
||||
private BookOptions bookOptions = new BookOptions();
|
||||
private EngineOptions engineOptions = new EngineOptions();
|
||||
private Game game = null;
|
||||
|
@ -94,10 +94,25 @@ public class DroidChessController {
|
|||
}
|
||||
computerPlayer.queueStartEngine(searchId, engine);
|
||||
searchId++;
|
||||
Game oldGame = game;
|
||||
game = new Game(gameTextListener, tcData);
|
||||
computerPlayer.uciNewGame();
|
||||
setPlayerNames(game);
|
||||
updateGameMode();
|
||||
game.resetModified(pgnOptions);
|
||||
autoSaveOldGame(oldGame, game.treeHashSignature);
|
||||
}
|
||||
|
||||
/** Save old game if has been modified since start/load of game and is
|
||||
* not equal to the new game. */
|
||||
private void autoSaveOldGame(Game oldGame, long newGameHash) {
|
||||
if (oldGame == null)
|
||||
return;
|
||||
String pgn = oldGame.tree.toPGN(pgnOptions);
|
||||
long oldGameOrigHash = oldGame.treeHashSignature;
|
||||
long oldGameCurrHash = Util.stringHash(pgn);
|
||||
if (oldGameCurrHash != oldGameOrigHash && oldGameCurrHash != newGameHash)
|
||||
gui.autoSaveGameIfAllowed(pgn);
|
||||
}
|
||||
|
||||
/** Start playing a new game. Should be called after newGame(). */
|
||||
|
@ -137,7 +152,7 @@ public class DroidChessController {
|
|||
}
|
||||
}
|
||||
|
||||
public GameMode getGameMode() {
|
||||
public final GameMode getGameMode() {
|
||||
return gameMode;
|
||||
}
|
||||
|
||||
|
@ -245,7 +260,7 @@ public class DroidChessController {
|
|||
}
|
||||
|
||||
/** Parse a string as FEN or PGN data. */
|
||||
public final synchronized void setFENOrPGN(String fenPgn) throws ChessParseError {
|
||||
public final synchronized void setFENOrPGN(String fenPgn, boolean setModified) throws ChessParseError {
|
||||
if (!fenPgn.isEmpty() && fenPgn.charAt(0) == '\ufeff')
|
||||
fenPgn = fenPgn.substring(1); // Remove BOM
|
||||
Game newGame = new Game(gameTextListener, game.timeController.tcData);
|
||||
|
@ -260,6 +275,7 @@ public class DroidChessController {
|
|||
newGame.tree.translateMoves();
|
||||
}
|
||||
searchId++;
|
||||
Game oldGame = game;
|
||||
game = newGame;
|
||||
gameTextListener.clear();
|
||||
updateGameMode();
|
||||
|
@ -268,6 +284,14 @@ public class DroidChessController {
|
|||
updateComputeThreads();
|
||||
gui.setSelection(-1);
|
||||
updateGUI();
|
||||
game.resetModified(pgnOptions);
|
||||
autoSaveOldGame(oldGame, game.treeHashSignature);
|
||||
if (setModified)
|
||||
game.treeHashSignature = oldGame.treeHashSignature;
|
||||
}
|
||||
|
||||
public final synchronized void setLastSaveHash(long hash) {
|
||||
game.treeHashSignature = hash;
|
||||
}
|
||||
|
||||
/** True if human's turn to make a move. (True in analysis mode.) */
|
||||
|
|
|
@ -27,11 +27,13 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import org.petero.droidfish.PGNOptions;
|
||||
import org.petero.droidfish.Util;
|
||||
import org.petero.droidfish.gamelogic.GameTree.Node;
|
||||
|
||||
public class Game {
|
||||
boolean pendingDrawOffer;
|
||||
public GameTree tree;
|
||||
long treeHashSignature; // Hash corresponding to "tree" when last saved to file
|
||||
TimeControl timeController;
|
||||
private boolean gamePaused;
|
||||
/** If true, add new moves as mainline moves. */
|
||||
|
@ -51,6 +53,8 @@ public class Game {
|
|||
/** De-serialize from input stream. */
|
||||
final void readFromStream(DataInputStream dis, int version) throws IOException, ChessParseError {
|
||||
tree.readFromStream(dis, version);
|
||||
if (version >= 4)
|
||||
treeHashSignature = dis.readLong();
|
||||
if (version >= 3)
|
||||
timeController.readFromStream(dis, version);
|
||||
updateTimeControl(true);
|
||||
|
@ -59,9 +63,15 @@ public class Game {
|
|||
/** Serialize to output stream. */
|
||||
final synchronized void writeToStream(DataOutputStream dos) throws IOException {
|
||||
tree.writeToStream(dos);
|
||||
dos.writeLong(treeHashSignature);
|
||||
timeController.writeToStream(dos);
|
||||
}
|
||||
|
||||
/** Set game to "not modified" state. */
|
||||
final void resetModified(PGNOptions options) {
|
||||
treeHashSignature = Util.stringHash(tree.toPGN(options));
|
||||
}
|
||||
|
||||
public final void setGamePaused(boolean gamePaused) {
|
||||
if (gamePaused != this.gamePaused) {
|
||||
this.gamePaused = gamePaused;
|
||||
|
|
|
@ -458,6 +458,15 @@ game with the selected position.
|
|||
|
||||
Saving a position to a FEN/EPD file has not been implemented.
|
||||
|
||||
## Autosave
|
||||
|
||||
When an action is performed that causes the current game to be discarded, the
|
||||
game is automatically saved in the file `DroidFish/pgn/.autosave.pgn` before
|
||||
being discarded. The autosave file has a maximum size of 20 games and the most
|
||||
recently autosaved game is stored first in the file. If the number of games
|
||||
becomes too large, the oldest stored game is removed from the file.
|
||||
|
||||
|
||||
## OI File Manager
|
||||
|
||||
If the [*OI File Manager*](https://play.google.com/store/apps/details?id=org.openintents.filemanager)
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user