DroidFish: Made it possible to set result when editing headers.

This commit is contained in:
Peter Osterlund 2016-12-26 23:54:40 +01:00
parent 7b98ca3c7b
commit 72f940de01
6 changed files with 254 additions and 120 deletions

View File

@ -93,5 +93,17 @@
android:inputType="text">
</EditText>
</TableRow>
<TableRow>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/header_result">
</TextView>
<Spinner
android:id="@+id/ed_game_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Spinner>
</TableRow>
</TableLayout>
</ScrollView>

View File

@ -150,6 +150,7 @@ you are not actively using the program.\
<string name="header_site">Site:</string>
<string name="header_date">Date:</string>
<string name="header_round">Round:</string>
<string name="header_result">Result:</string>
<string name="comment_before">Before:</string>
<string name="comment_move">Move:</string>
<string name="comment_after">After:</string>

View File

@ -151,6 +151,7 @@ import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
@ -2824,88 +2825,12 @@ public class DroidFish extends Activity
builder.setItems(lst.toArray(new CharSequence[lst.size()]), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
switch (actions.get(item)) {
case EDIT_HEADERS: {
final TreeMap<String,String> headers = new TreeMap<String,String>();
ctrl.getHeaders(headers);
AlertDialog.Builder builder = new AlertDialog.Builder(DroidFish.this);
builder.setTitle(R.string.edit_headers);
View content = View.inflate(DroidFish.this, R.layout.edit_headers, null);
builder.setView(content);
final TextView event, site, date, round, white, black;
event = (TextView)content.findViewById(R.id.ed_header_event);
site = (TextView)content.findViewById(R.id.ed_header_site);
date = (TextView)content.findViewById(R.id.ed_header_date);
round = (TextView)content.findViewById(R.id.ed_header_round);
white = (TextView)content.findViewById(R.id.ed_header_white);
black = (TextView)content.findViewById(R.id.ed_header_black);
event.setText(headers.get("Event"));
site .setText(headers.get("Site"));
date .setText(headers.get("Date"));
round.setText(headers.get("Round"));
white.setText(headers.get("White"));
black.setText(headers.get("Black"));
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, new Dialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
headers.put("Event", event.getText().toString().trim());
headers.put("Site", site .getText().toString().trim());
headers.put("Date", date .getText().toString().trim());
headers.put("Round", round.getText().toString().trim());
headers.put("White", white.getText().toString().trim());
headers.put("Black", black.getText().toString().trim());
ctrl.setHeaders(headers);
setBoardFlip(true);
}
});
builder.show();
case EDIT_HEADERS:
editHeaders();
break;
}
case EDIT_COMMENTS: {
AlertDialog.Builder builder = new AlertDialog.Builder(DroidFish.this);
builder.setTitle(R.string.edit_comments);
View content = View.inflate(DroidFish.this, R.layout.edit_comments, null);
builder.setView(content);
DroidChessController.CommentInfo commInfo = ctrl.getComments();
final TextView preComment, moveView, nag, postComment;
preComment = (TextView)content.findViewById(R.id.ed_comments_pre);
moveView = (TextView)content.findViewById(R.id.ed_comments_move);
nag = (TextView)content.findViewById(R.id.ed_comments_nag);
postComment = (TextView)content.findViewById(R.id.ed_comments_post);
preComment.setText(commInfo.preComment);
postComment.setText(commInfo.postComment);
moveView.setText(commInfo.move);
String nagStr = Node.nagStr(commInfo.nag).trim();
if ((nagStr.length() == 0) && (commInfo.nag > 0))
nagStr = String.format(Locale.US, "%d", commInfo.nag);
nag.setText(nagStr);
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, new Dialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
String pre = preComment.getText().toString().trim();
String post = postComment.getText().toString().trim();
int nagVal = Node.strToNag(nag.getText().toString());
DroidChessController.CommentInfo commInfo = new DroidChessController.CommentInfo();
commInfo.preComment = pre;
commInfo.postComment = post;
commInfo.nag = nagVal;
ctrl.setComments(commInfo);
}
});
builder.show();
case EDIT_COMMENTS:
editComments();
break;
}
case ADD_ECO:
ctrl.addECO();
break;
@ -2930,6 +2855,102 @@ public class DroidFish extends Activity
return alert;
}
/** Let the user edit the PGN headers. */
private void editHeaders() {
final TreeMap<String,String> headers = new TreeMap<String,String>();
ctrl.getHeaders(headers);
AlertDialog.Builder builder = new AlertDialog.Builder(DroidFish.this);
builder.setTitle(R.string.edit_headers);
View content = View.inflate(DroidFish.this, R.layout.edit_headers, null);
builder.setView(content);
final TextView event, site, date, round, white, black;
event = (TextView)content.findViewById(R.id.ed_header_event);
site = (TextView)content.findViewById(R.id.ed_header_site);
date = (TextView)content.findViewById(R.id.ed_header_date);
round = (TextView)content.findViewById(R.id.ed_header_round);
white = (TextView)content.findViewById(R.id.ed_header_white);
black = (TextView)content.findViewById(R.id.ed_header_black);
event.setText(headers.get("Event"));
site .setText(headers.get("Site"));
date .setText(headers.get("Date"));
round.setText(headers.get("Round"));
white.setText(headers.get("White"));
black.setText(headers.get("Black"));
final Spinner gameResult = (Spinner)content.findViewById(R.id.ed_game_result);
final String[] items = new String[]{"1-0", "1/2-1/2", "0-1", "*"};
ArrayAdapter<CharSequence> adapt =
new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item, items);
adapt.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
gameResult.setAdapter(adapt);
gameResult.setSelection(Arrays.asList(items).indexOf(headers.get("Result")));
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, new Dialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
headers.put("Event", event.getText().toString().trim());
headers.put("Site", site .getText().toString().trim());
headers.put("Date", date .getText().toString().trim());
headers.put("Round", round.getText().toString().trim());
headers.put("White", white.getText().toString().trim());
headers.put("Black", black.getText().toString().trim());
int p = gameResult.getSelectedItemPosition();
String res = (p >= 0 && p < items.length) ? items[p] : "";
if (!res.isEmpty())
headers.put("Result", res);
ctrl.setHeaders(headers);
setBoardFlip(true);
}
});
builder.show();
}
/** Let the user edit comments related to a move. */
private void editComments() {
AlertDialog.Builder builder = new AlertDialog.Builder(DroidFish.this);
builder.setTitle(R.string.edit_comments);
View content = View.inflate(DroidFish.this, R.layout.edit_comments, null);
builder.setView(content);
DroidChessController.CommentInfo commInfo = ctrl.getComments();
final TextView preComment, moveView, nag, postComment;
preComment = (TextView)content.findViewById(R.id.ed_comments_pre);
moveView = (TextView)content.findViewById(R.id.ed_comments_move);
nag = (TextView)content.findViewById(R.id.ed_comments_nag);
postComment = (TextView)content.findViewById(R.id.ed_comments_post);
preComment.setText(commInfo.preComment);
postComment.setText(commInfo.postComment);
moveView.setText(commInfo.move);
String nagStr = Node.nagStr(commInfo.nag).trim();
if ((nagStr.length() == 0) && (commInfo.nag > 0))
nagStr = String.format(Locale.US, "%d", commInfo.nag);
nag.setText(nagStr);
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, new Dialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
String pre = preComment.getText().toString().trim();
String post = postComment.getText().toString().trim();
int nagVal = Node.strToNag(nag.getText().toString());
DroidChessController.CommentInfo commInfo = new DroidChessController.CommentInfo();
commInfo.preComment = pre;
commInfo.postComment = post;
commInfo.nag = nagVal;
ctrl.setComments(commInfo);
}
});
builder.show();
}
private final Dialog thinkingMenuDialog() {
final int ADD_ANALYSIS = 0;
final int MULTIPV_SET = 1;

View File

@ -623,8 +623,13 @@ public class DroidChessController {
/** Set PGN header tags and values. */
public final synchronized void setHeaders(Map<String,String> headers) {
game.tree.setHeaders(headers);
boolean resultChanged = game.tree.setHeaders(headers);
gameTextListener.clear();
if (resultChanged) {
abortSearch();
updateComputeThreads();
setSelection();
}
updateGUI();
}

View File

@ -290,24 +290,7 @@ public class GameTree {
/** Walks the game tree in PGN export order. */
public final void pgnTreeWalker(PGNOptions options, PgnToken.PgnTokenReceiver out) {
// Go to end of mainline to evaluate PGN result string.
String pgnResultString;
{
List<Integer> currPath = new ArrayList<Integer>();
while (currentNode != rootNode) {
Node child = currentNode;
goBack();
int childNum = currentNode.children.indexOf(child);
currPath.add(childNum);
}
while (variations().size() > 0)
goForward(0, false);
pgnResultString = getPGNResultString();
while (currentNode != rootNode)
goBack();
for (int i = currPath.size() - 1; i >= 0; i--)
goForward(currPath.get(i), false);
}
String pgnResultString = getPGNResultStringMainLine();
// Write seven tag roster
addTagPair(out, "Event", event);
@ -600,24 +583,8 @@ public class GameTree {
while (variations().size() > 0)
goForward(0);
GameState state = getGameState();
if (state == GameState.ALIVE) {
if (result.equals("1-0")) {
if (currentPos.whiteMove) {
currentNode.playerAction = "resign";
} else {
addMove("--", "resign", 0, "", "");
}
} else if (result.equals("0-1")) {
if (!currentPos.whiteMove) {
currentNode.playerAction = "resign";
} else {
addMove("--", "resign", 0, "", "");
}
} else if (result.equals("1/2-1/2") || result.equals("1/2")) {
currentNode.playerAction = "draw offer";
addMove("--", "draw accept", 0, "", "");
}
}
if (state == GameState.ALIVE)
addResult(result);
// Go back to the root
while (currentNode != rootNode)
goBack();
@ -627,6 +594,26 @@ public class GameTree {
return true;
}
/** Add game result to the tree. currentNode must be at the end of the main line. */
private void addResult(String result) {
if (result.equals("1-0")) {
if (currentPos.whiteMove) {
currentNode.playerAction = "resign";
} else {
addMove("--", "resign", 0, "", "");
}
} else if (result.equals("0-1")) {
if (!currentPos.whiteMove) {
currentNode.playerAction = "resign";
} else {
addMove("--", "resign", 0, "", "");
}
} else if (result.equals("1/2-1/2") || result.equals("1/2")) {
currentNode.playerAction = "draw offer";
addMove("--", "draw accept", 0, "", "");
}
}
/** Serialize to output stream. */
public final void writeToStream(DataOutputStream dos) throws IOException {
dos.writeUTF(event);
@ -928,6 +915,7 @@ public class GameTree {
return ret;
}
/** Get PGN result string corresponding to the current position. */
public final String getPGNResultString() {
String gameResult = "*";
switch (getGameState()) {
@ -953,6 +941,25 @@ public class GameTree {
return gameResult;
}
/** Evaluate PGN result string at the end of the main line. */
public final String getPGNResultStringMainLine() {
List<Integer> currPath = new ArrayList<Integer>();
while (currentNode != rootNode) {
Node child = currentNode;
goBack();
int childNum = currentNode.children.indexOf(child);
currPath.add(childNum);
}
while (variations().size() > 0)
goForward(0, false);
String res = getPGNResultString();
while (currentNode != rootNode)
goBack();
for (int i = currPath.size() - 1; i >= 0; i--)
goForward(currPath.get(i), false);
return res;
}
private static final boolean insufficientMaterial(Position pos) {
if (pos.nPieces(Piece.WQUEEN) > 0) return false;
if (pos.nPieces(Piece.WROOK) > 0) return false;
@ -1497,8 +1504,10 @@ public class GameTree {
}
/** Set PGN header tags and values. Setting a non-required
* tag to null causes it to be removed. */
void setHeaders(Map<String,String> headers) {
* tag to null causes it to be removed.
* @return True if game result changes, false otherwise. */
boolean setHeaders(Map<String,String> headers) {
boolean resultChanged = false;
for (Entry<String, String> entry : headers.entrySet()) {
String tag = entry.getKey();
String val = entry.getValue();
@ -1508,7 +1517,44 @@ public class GameTree {
else if (tag.equals("Round")) round = val;
else if (tag.equals("White")) white = val;
else if (tag.equals("Black")) black = val;
else {
else if (tag.equals("Result")) {
List<Integer> currPath = new ArrayList<Integer>();
while (currentNode != rootNode) {
Node child = currentNode;
goBack();
int childNum = currentNode.children.indexOf(child);
currPath.add(childNum);
}
while (variations().size() > 0)
goForward(0, false);
if (!val.equals(getPGNResultString())) {
resultChanged = true;
GameState state = getGameState();
switch (state) {
case ALIVE:
case DRAW_50:
case DRAW_AGREE:
case DRAW_REP:
case RESIGN_BLACK:
case RESIGN_WHITE:
currentNode.playerAction = "";
if ("--".equals(currentNode.moveStr)) {
Node child = currentNode;
goBack();
int childNum = currentNode.children.indexOf(child);
deleteVariation(childNum);
}
addResult(val);
break;
default:
break;
}
}
while (currentNode != rootNode)
goBack();
for (int i = currPath.size() - 1; i >= 0; i--)
goForward(currPath.get(i), false);
} else {
if (val != null) {
boolean found = false;
for (TagPair t : tagPairs) {
@ -1534,6 +1580,7 @@ public class GameTree {
}
}
}
return resultChanged;
}
/** Get PGN header tags and values. */
@ -1544,6 +1591,7 @@ public class GameTree {
headers.put("Round", round);
headers.put("White", white);
headers.put("Black", black);
headers.put("Result", getPGNResultStringMainLine());
if (!timeControl.equals("?"))
headers.put("TimeControl", timeControl);
if (!whiteTimeControl.equals("?"))

View File

@ -803,4 +803,51 @@ public class GameTreeTest extends TestCase {
assertEquals(3140, tf.timeControl);
assertEquals(2718, tf.increment);
}
public final void testHeaders() throws Throwable {
PGNOptions options = new PGNOptions();
options.imp.variations = true;
options.imp.comments = true;
options.imp.nag = true;
{
GameTree gt = new GameTree(null);
boolean res = gt.readPGN("[White \"a\"][Black \"b\"] f4 *", options);
assertEquals(true, res);
TreeMap<String,String> headers = new TreeMap<String,String>();
headers.put("Event", "test");
gt.setHeaders(headers);
TreeMap<String,String> newHeaders = new TreeMap<String,String>();
gt.getHeaders(newHeaders);
assertEquals("test", newHeaders.get("Event"));
for (int i = 0; i < 2; i++) {
for (String r : new String[]{"1-0", "1/2-1/2", "0-1", "*"}) {
headers.clear();
headers.put("Result", r);
gt.setHeaders(headers);
newHeaders.clear();
gt.getHeaders(newHeaders);
assertEquals(r, newHeaders.get("Result"));
}
}
}
{
GameTree gt = new GameTree(null);
gt.readPGN("f3 e5 g4 Qh4", options);
TreeMap<String,String> headers = new TreeMap<String,String>();
gt.getHeaders(headers);
assertEquals("0-1", headers.get("Result"));
for (String r : new String[]{"1-0", "1/2-1/2", "0-1", "*"}) {
headers.clear();
headers.put("Result", r);
gt.setHeaders(headers);
headers.clear();
gt.getHeaders(headers);
assertEquals("0-1", headers.get("Result"));
}
}
}
}