mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2024-11-23 11:31:33 +01:00
DroidFish: English text to speech support for announcing moves.
This commit is contained in:
parent
38295b516f
commit
0c33791ddd
|
@ -12,6 +12,7 @@
|
|||
<string name="book_line_length_default">1000000</string>
|
||||
<string name="viewPieceType_default">1</string>
|
||||
<string name="autoDelay_default">5000</string>
|
||||
<string name="move_announce_type_default">off</string>
|
||||
<string name="cpu_warning">\
|
||||
<b>CPU Usage</b>\n\
|
||||
If you leave DroidFish running in the background and <i>GameMode</i> is set to \
|
||||
|
@ -219,6 +220,9 @@ you are not actively using the program.\
|
|||
<string name="network_port">Port</string>
|
||||
<string name="network_engine">Network Engine</string>
|
||||
<string name="failed_to_start_engine">Failed to start engine</string>
|
||||
<string name="tts_failed_to_init">Failed to initialize text to speech</string>
|
||||
<string name="tts_data_missing">Text to speech data missing</string>
|
||||
<string name="tts_not_supported_for_lang">Text to speech not supported for this language</string>
|
||||
<string name="engine_terminated">Engine terminated</string>
|
||||
<string name="uci_protocol_error">UCI protocol error</string>
|
||||
<string name="network_engine_config_error">Network engine configuration error</string>
|
||||
|
@ -296,8 +300,8 @@ you are not actively using the program.\
|
|||
<string name="prefs_autoScrollTitle_summary">Auto scroll titlebar if player names are too long</string>
|
||||
<string name="prefs_quickMoveInput_title">Quick Move Input</string>
|
||||
<string name="prefs_quickMoveInput_summary">From and To squares can be touched in any order. Move is played as soon as uniquely defined.</string>
|
||||
<string name="prefs_soundEnabled_title">Enable Sounds</string>
|
||||
<string name="prefs_soundEnabled_summary">Play sound when computer makes a move</string>
|
||||
<string name="prefs_moveAnnounceType_title">Move Announcement</string>
|
||||
<string name="prefs_moveAnnounceType_summary">Announcement sound when computer makes a move</string>
|
||||
<string name="prefs_vibrateEnabled_title">Enable Vibration</string>
|
||||
<string name="prefs_vibrateEnabled_summary">Vibrate when computer makes a move</string>
|
||||
<string name="prefs_fullScreenMode_title">Fullscreen Mode</string>
|
||||
|
@ -696,4 +700,14 @@ you are not actively using the program.\
|
|||
<item>selectEngine</item>
|
||||
<item>engineOptions</item>
|
||||
</string-array>
|
||||
<string-array name="move_announce_type_values">
|
||||
<item>off</item>
|
||||
<item>sound</item>
|
||||
<item>speech_en</item>
|
||||
</string-array>
|
||||
<string-array name="move_announce_type_texts">
|
||||
<item>Off</item>
|
||||
<item>Play sound</item>
|
||||
<item>English Speech</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -157,12 +157,14 @@
|
|||
android:summary="@string/prefs_vibrateEnabled_summary"
|
||||
android:defaultValue="false">
|
||||
</CheckBoxPreference>
|
||||
<CheckBoxPreference
|
||||
android:key="soundEnabled"
|
||||
android:title="@string/prefs_soundEnabled_title"
|
||||
android:summary="@string/prefs_soundEnabled_summary"
|
||||
android:defaultValue="false">
|
||||
</CheckBoxPreference>
|
||||
<ListPreference
|
||||
android:key="moveAnnounceType"
|
||||
android:title="@string/prefs_moveAnnounceType_title"
|
||||
android:summary="@string/prefs_moveAnnounceType_summary"
|
||||
android:entryValues="@array/move_announce_type_values"
|
||||
android:entries="@array/move_announce_type_texts"
|
||||
android:defaultValue="@string/move_announce_type_default">
|
||||
</ListPreference>
|
||||
<CheckBoxPreference
|
||||
android:key="wakeLock"
|
||||
android:title="@string/prefs_wakeLock_title"
|
||||
|
|
|
@ -225,7 +225,7 @@ public class DroidFish extends Activity
|
|||
private boolean autoScrollMoveList;
|
||||
|
||||
private boolean leftHanded;
|
||||
private boolean soundEnabled;
|
||||
private String moveAnnounceType;
|
||||
private MediaPlayer moveSound;
|
||||
private boolean vibrateEnabled;
|
||||
private boolean animateMoves;
|
||||
|
@ -276,6 +276,8 @@ public class DroidFish extends Activity
|
|||
private boolean guideShowOnStart;
|
||||
private TourGuide tourGuide;
|
||||
|
||||
private Speech speech;
|
||||
|
||||
|
||||
/** Defines all configurable button actions. */
|
||||
private ActionFactory actionFactory = new ActionFactory() {
|
||||
|
@ -485,6 +487,8 @@ public class DroidFish extends Activity
|
|||
ctrl.shutdownEngine();
|
||||
ctrl = new DroidChessController(this, gameTextListener, pgnOptions);
|
||||
egtbForceReload = true;
|
||||
if (speech == null)
|
||||
speech = new Speech();
|
||||
readPrefs();
|
||||
TimeControlData tcData = new TimeControlData();
|
||||
tcData.setTimeControl(timeControl, movesPerSession, timeIncrement);
|
||||
|
@ -1147,6 +1151,8 @@ public class DroidFish extends Activity
|
|||
if (ctrl != null)
|
||||
ctrl.shutdownEngine();
|
||||
setNotification(false);
|
||||
if (speech != null)
|
||||
speech.shutdown();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
@ -1210,7 +1216,8 @@ public class DroidFish extends Activity
|
|||
if (config.orientation == Configuration.ORIENTATION_PORTRAIT)
|
||||
statusFontSize = Math.min(statusFontSize, 16);
|
||||
status.setTextSize(statusFontSize);
|
||||
soundEnabled = settings.getBoolean("soundEnabled", false);
|
||||
moveAnnounceType = settings.getString("moveAnnounceType", "off");
|
||||
initSpeech();
|
||||
vibrateEnabled = settings.getBoolean("vibrateEnabled", false);
|
||||
animateMoves = settings.getBoolean("animateMoves", true);
|
||||
autoScrollTitle = settings.getBoolean("autoScrollTitle", true);
|
||||
|
@ -3766,17 +3773,27 @@ public class DroidFish extends Activity
|
|||
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
/** Initialize text to speech if enabled in settings. */
|
||||
private void initSpeech() {
|
||||
if (moveAnnounceType.startsWith("speech_"))
|
||||
speech.initialize(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computerMoveMade() {
|
||||
if (soundEnabled) {
|
||||
if (moveSound != null)
|
||||
moveSound.release();
|
||||
try {
|
||||
moveSound = MediaPlayer.create(this, R.raw.movesound);
|
||||
public void movePlayed(Position pos, Move move, boolean computerMove) {
|
||||
if ("sound".equals(moveAnnounceType)) {
|
||||
if (computerMove) {
|
||||
if (moveSound != null)
|
||||
moveSound.start();
|
||||
} catch (NotFoundException ex) {
|
||||
moveSound.release();
|
||||
try {
|
||||
moveSound = MediaPlayer.create(this, R.raw.movesound);
|
||||
if (moveSound != null)
|
||||
moveSound.start();
|
||||
} catch (NotFoundException ex) {
|
||||
}
|
||||
}
|
||||
} else if (moveAnnounceType.startsWith("speech_")) {
|
||||
speech.say(pos, move, moveAnnounceType.substring(7));
|
||||
}
|
||||
if (vibrateEnabled) {
|
||||
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
||||
|
|
|
@ -79,8 +79,8 @@ public interface GUIInterface {
|
|||
/** Report UCI engine error message. */
|
||||
public void reportEngineError(String errMsg);
|
||||
|
||||
/** Called when computer made a move. GUI can notify user, for example by playing a sound. */
|
||||
public void computerMoveMade();
|
||||
/** Called when a move is played. GUI can notify user, for example by playing a sound. */
|
||||
public void movePlayed(Position pos, Move move, boolean computerMove);
|
||||
|
||||
/** Report remaining thinking time to GUI. */
|
||||
public void setRemainingTime(int wTime, int bTime, int nextUpdate);
|
||||
|
|
209
DroidFish/src/org/petero/droidfish/Speech.java
Normal file
209
DroidFish/src/org/petero/droidfish/Speech.java
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
DroidFish - An Android chess program.
|
||||
Copyright (C) 2016 Peter Österlund, peterosterlund2@gmail.com
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.petero.droidfish;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.petero.droidfish.gamelogic.Move;
|
||||
import org.petero.droidfish.gamelogic.Piece;
|
||||
import org.petero.droidfish.gamelogic.Position;
|
||||
import org.petero.droidfish.gamelogic.TextIO;
|
||||
|
||||
import android.content.Context;
|
||||
import android.speech.tts.TextToSpeech;
|
||||
import android.speech.tts.TextToSpeech.OnInitListener;
|
||||
import android.widget.Toast;
|
||||
|
||||
/** Handles text to speech translation. */
|
||||
public class Speech {
|
||||
private TextToSpeech tts;
|
||||
boolean initialized = false;
|
||||
boolean supported = false;
|
||||
String toSpeak = null;
|
||||
|
||||
public void initialize(final Context context) {
|
||||
if (initialized)
|
||||
return;
|
||||
tts = new TextToSpeech(context, new OnInitListener() {
|
||||
@Override
|
||||
public void onInit(int status) {
|
||||
initialized = true;
|
||||
int toast = -1;
|
||||
if (status == TextToSpeech.SUCCESS) {
|
||||
int code = tts.setLanguage(Locale.US);
|
||||
switch (code) {
|
||||
case TextToSpeech.LANG_AVAILABLE:
|
||||
case TextToSpeech.LANG_COUNTRY_AVAILABLE:
|
||||
case TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE:
|
||||
supported = true;
|
||||
say(toSpeak);
|
||||
break;
|
||||
case TextToSpeech.LANG_MISSING_DATA:
|
||||
toast = R.string.tts_data_missing;
|
||||
break;
|
||||
case TextToSpeech.LANG_NOT_SUPPORTED:
|
||||
toast = R.string.tts_not_supported_for_lang;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
toast = R.string.tts_failed_to_init;
|
||||
}
|
||||
if (toast != -1)
|
||||
Toast.makeText(context, toast, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void say(String text) {
|
||||
if (initialized) {
|
||||
if (supported && text != null)
|
||||
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
|
||||
toSpeak = null;
|
||||
} else {
|
||||
toSpeak = text;
|
||||
}
|
||||
}
|
||||
|
||||
/** Immediately cancel all speech output. */
|
||||
public void flushQueue() {
|
||||
toSpeak = null;
|
||||
if (tts != null)
|
||||
tts.stop();
|
||||
}
|
||||
|
||||
/** Shut down the speech engine. */
|
||||
public void shutdown() {
|
||||
if (tts != null) {
|
||||
tts.shutdown();
|
||||
tts = null;
|
||||
initialized = false;
|
||||
supported = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert move "move" in position "pos" to a sentence and speak it. */
|
||||
public void say(Position pos, Move move, String langStr) {
|
||||
String s = moveToText(pos, move, langStr);
|
||||
// System.out.printf("%.3f Speech.say(): %s\n", System.currentTimeMillis() * 1e-3, s);
|
||||
if (!s.isEmpty())
|
||||
say(s);
|
||||
}
|
||||
|
||||
/** Convert move "move" in position "pos" to a sentence that can be spoken. */
|
||||
public static String moveToText(Position pos, Move move, String langStr) {
|
||||
if (move == null || !langStr.equals("en"))
|
||||
return "";
|
||||
|
||||
String moveStr = TextIO.moveToString(pos, move, false, false);
|
||||
int piece = Piece.makeWhite(pos.getPiece(move.from));
|
||||
boolean capture = pos.getPiece(move.to) != Piece.EMPTY;
|
||||
boolean promotion = move.promoteTo != Piece.EMPTY;
|
||||
boolean check = moveStr.endsWith("+");
|
||||
boolean checkMate = moveStr.endsWith("#");
|
||||
boolean castle = false;
|
||||
|
||||
if (piece == Piece.WPAWN && !capture) {
|
||||
int fx = Position.getX(move.from);
|
||||
int tx = Position.getX(move.to);
|
||||
if (fx != tx)
|
||||
capture = true; // En passant
|
||||
}
|
||||
|
||||
StringBuilder sentence = new StringBuilder();
|
||||
|
||||
if (piece == Piece.WKING) {
|
||||
int fx = Position.getX(move.from);
|
||||
int tx = Position.getX(move.to);
|
||||
if (fx == 4 && tx == 6) {
|
||||
sentence.append("Short castle");
|
||||
castle = true;
|
||||
} else if (fx == 4 && (tx == 2)) {
|
||||
sentence.append("Long castle");
|
||||
castle = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!castle) {
|
||||
boolean pawnMove = piece == Piece.WPAWN;
|
||||
if (!pawnMove)
|
||||
sentence.append(pieceName(piece)).append(' ');
|
||||
|
||||
if (capture) {
|
||||
int i = moveStr.indexOf("x");
|
||||
String from = moveStr.substring(pawnMove ? 0 : 1, i);
|
||||
if (!from.isEmpty())
|
||||
sentence.append(getFromWord(from)).append(' ');
|
||||
String to = moveStr.substring(i + 1, i + 3);
|
||||
sentence.append(to.startsWith("e") ? "take " : "takes ");
|
||||
sentence.append(to).append(' ');
|
||||
} else {
|
||||
int nSkip = (promotion ? 1 : 0) + ((check | checkMate) ? 1 : 0);
|
||||
int i = moveStr.length() - nSkip;
|
||||
String from = moveStr.substring(pawnMove ? 0 : 1, i - 2);
|
||||
if (!from.isEmpty())
|
||||
sentence.append(from).append(' ');
|
||||
String to = moveStr.substring(i - 2, i);
|
||||
sentence.append(to).append(' ');
|
||||
}
|
||||
|
||||
if (promotion)
|
||||
sentence.append(pieceName(move.promoteTo)).append(' ');
|
||||
}
|
||||
|
||||
if (checkMate) {
|
||||
removeLastSpace(sentence);
|
||||
sentence.append(". Check mate!");
|
||||
} else if (check) {
|
||||
removeLastSpace(sentence);
|
||||
sentence.append(". Check!");
|
||||
}
|
||||
|
||||
return sentence.toString().trim();
|
||||
}
|
||||
|
||||
/** Get the name of a non-pawn piece. Return empty string if no such piece. */
|
||||
private static String pieceName(int piece) {
|
||||
piece = Piece.makeWhite(piece);
|
||||
switch (piece) {
|
||||
case Piece.WKING: return "King";
|
||||
case Piece.WQUEEN: return "Queen";
|
||||
case Piece.WROOK: return "Rook";
|
||||
case Piece.WBISHOP: return "Bishop";
|
||||
case Piece.WKNIGHT: return "Knight";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
/** Transform a "from" file or file+rank to a word. */
|
||||
private static String getFromWord(String from) {
|
||||
if ("a".equals(from))
|
||||
return "ae";
|
||||
return from;
|
||||
}
|
||||
|
||||
/** If the last character in the StringBuilder is a space, remove it. */
|
||||
private static void removeLastSpace(StringBuilder sb) {
|
||||
int len = sb.length();
|
||||
if (len > 0 && sb.charAt(len - 1) == ' ')
|
||||
sb.setLength(len - 1);
|
||||
}
|
||||
}
|
|
@ -1023,10 +1023,10 @@ public class DroidChessController {
|
|||
return;
|
||||
searchId++;
|
||||
Position oldPos = new Position(game.currPos());
|
||||
game.processString(cmd);
|
||||
Pair<Boolean,Move> res = game.processString(cmd);
|
||||
ponderMove = ponder;
|
||||
updateGameMode();
|
||||
gui.computerMoveMade();
|
||||
gui.movePlayed(game.prevPos(), res.second, true);
|
||||
listener.clearSearchInfo(searchId);
|
||||
updateComputeThreads();
|
||||
setSelection();
|
||||
|
@ -1113,7 +1113,8 @@ public class DroidChessController {
|
|||
}
|
||||
if (m.promoteTo == promoteTo) {
|
||||
String strMove = TextIO.moveToString(pos, m, false, false, moves);
|
||||
game.processString(strMove);
|
||||
Pair<Boolean,Move> res = game.processString(strMove);
|
||||
gui.movePlayed(game.prevPos(), res.second, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,18 +133,19 @@ public class Game {
|
|||
/**
|
||||
* Update the game state according to move/command string from a player.
|
||||
* @param str The move or command to process.
|
||||
* @return True if str was understood, false otherwise.
|
||||
*/
|
||||
public final boolean processString(String str) {
|
||||
* @return Pair where first item is true if str was understood, false otherwise.
|
||||
* Second item is move played, or null if no move was played. */
|
||||
/** Like processString, but also returns the move played, if any. */
|
||||
public final Pair<Boolean, Move> processString(String str) {
|
||||
if (getGameState() != GameState.ALIVE)
|
||||
return false;
|
||||
return new Pair<Boolean,Move>(false, null);
|
||||
if (str.startsWith("draw ")) {
|
||||
String drawCmd = str.substring(str.indexOf(" ") + 1);
|
||||
handleDrawCmd(drawCmd, true);
|
||||
return true;
|
||||
Move m = handleDrawCmd(drawCmd, true);
|
||||
return new Pair<Boolean,Move>(true, m);
|
||||
} else if (str.equals("resign")) {
|
||||
addToGameTree(new Move(0, 0, 0), "resign");
|
||||
return true;
|
||||
return new Pair<Boolean,Move>(true, null);
|
||||
}
|
||||
|
||||
Move m = TextIO.UCIstringToMove(str);
|
||||
|
@ -154,10 +155,10 @@ public class Game {
|
|||
if (m == null)
|
||||
m = TextIO.stringToMove(currPos(), str);
|
||||
if (m == null)
|
||||
return false;
|
||||
return new Pair<Boolean,Move>(false, null);
|
||||
|
||||
addToGameTree(m, pendingDrawOffer ? "draw offer" : "");
|
||||
return true;
|
||||
return new Pair<Boolean,Move>(true, m);
|
||||
}
|
||||
|
||||
/** Try claim a draw using a command string. Does not play the move involved
|
||||
|
@ -455,7 +456,8 @@ public class Game {
|
|||
return new Pair<Position, ArrayList<Move>>(pos, mList);
|
||||
}
|
||||
|
||||
private final void handleDrawCmd(String drawCmd, boolean playDrawMove) {
|
||||
private final Move handleDrawCmd(String drawCmd, boolean playDrawMove) {
|
||||
Move ret = null;
|
||||
Position pos = tree.currentPos;
|
||||
if (drawCmd.startsWith("rep") || drawCmd.startsWith("50")) {
|
||||
boolean rep = drawCmd.startsWith("rep");
|
||||
|
@ -509,18 +511,19 @@ public class Game {
|
|||
} else {
|
||||
pendingDrawOffer = true;
|
||||
if (m != null && playDrawMove) {
|
||||
processString(ms);
|
||||
ret = processString(ms).second;
|
||||
}
|
||||
}
|
||||
} else if (drawCmd.startsWith("offer ")) {
|
||||
pendingDrawOffer = true;
|
||||
String ms = drawCmd.substring(drawCmd.indexOf(" ") + 1);
|
||||
if (TextIO.stringToMove(pos, ms) != null) {
|
||||
processString(ms);
|
||||
ret = processString(ms).second;
|
||||
}
|
||||
} else if (drawCmd.equals("accept")) {
|
||||
if (haveDrawOffer())
|
||||
addToGameTree(new Move(0, 0, 0), "draw accept");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,36 +39,48 @@ public class GameTest extends TestCase {
|
|||
Game game = new Game(null, new TimeControlData());
|
||||
assertEquals(false, game.haveDrawOffer());
|
||||
|
||||
boolean res = game.processString("e4");
|
||||
Pair<Boolean,Move> p = game.processString("e4");
|
||||
boolean res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(TextIO.UCIstringToMove("e2e4"), p.second);
|
||||
assertEquals(false, game.haveDrawOffer());
|
||||
|
||||
res = game.processString("draw offer e5");
|
||||
p = game.processString("draw offer e5");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(TextIO.UCIstringToMove("e7e5"), p.second);
|
||||
assertEquals(true, game.haveDrawOffer());
|
||||
assertEquals(Game.GameState.ALIVE, game.getGameState()); // Draw offer does not imply draw
|
||||
assertEquals(Piece.BPAWN, game.currPos().getPiece(Position.getSquare(4, 4))); // e5 move made
|
||||
|
||||
res = game.processString("draw offer Nf3");
|
||||
p = game.processString("draw offer Nf3");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(TextIO.UCIstringToMove("g1f3"), p.second);
|
||||
assertEquals(true, game.haveDrawOffer());
|
||||
assertEquals(Game.GameState.ALIVE, game.getGameState()); // Draw offer does not imply draw
|
||||
assertEquals(Piece.WKNIGHT, game.currPos().getPiece(Position.getSquare(5, 2))); // Nf3 move made
|
||||
|
||||
res = game.processString("Nc6");
|
||||
p = game.processString("Nc6");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(TextIO.UCIstringToMove("b8c6"), p.second);
|
||||
assertEquals(false, game.haveDrawOffer());
|
||||
assertEquals(Game.GameState.ALIVE, game.getGameState());
|
||||
assertEquals(Piece.BKNIGHT, game.currPos().getPiece(Position.getSquare(2, 5))); // Nc6 move made
|
||||
|
||||
res = game.processString("draw offer Bb5");
|
||||
p = game.processString("draw offer Bb5");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(TextIO.UCIstringToMove("f1b5"), p.second);
|
||||
assertEquals(true, game.haveDrawOffer());
|
||||
assertEquals(Game.GameState.ALIVE, game.getGameState());
|
||||
assertEquals(Piece.WBISHOP, game.currPos().getPiece(Position.getSquare(1, 4))); // Bb5 move made
|
||||
|
||||
res = game.processString("draw accept");
|
||||
p = game.processString("draw accept");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(null, p.second);
|
||||
assertEquals(Game.GameState.DRAW_AGREE, game.getGameState()); // Draw by agreement
|
||||
|
||||
game.undoMove(); // Undo "draw accept"
|
||||
|
@ -100,11 +112,15 @@ public class GameTest extends TestCase {
|
|||
assertEquals(false, game.haveDrawOffer());
|
||||
assertEquals(Game.GameState.ALIVE, game.getGameState());
|
||||
|
||||
res = game.processString("draw offer e5");
|
||||
p = game.processString("draw offer e5");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(null, p.second);
|
||||
assertEquals(TextIO.startPosFEN, TextIO.toFEN(game.currPos())); // Move invalid, not executed
|
||||
res = game.processString("e4");
|
||||
p = game.processString("e4");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(TextIO.UCIstringToMove("e2e4"), p.second);
|
||||
assertEquals(true, game.haveDrawOffer()); // Previous draw offer still valid
|
||||
assertEquals(Piece.WPAWN, game.currPos().getPiece(Position.getSquare(4, 3))); // e4 move made
|
||||
|
||||
|
@ -126,15 +142,20 @@ public class GameTest extends TestCase {
|
|||
public void testDraw50() throws ChessParseError {
|
||||
Game game = new Game(null, new TimeControlData());
|
||||
assertEquals(false, game.haveDrawOffer());
|
||||
boolean res = game.processString("draw 50");
|
||||
Pair<Boolean,Move> p = game.processString("draw 50");
|
||||
boolean res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(null, p.second);
|
||||
assertEquals(Game.GameState.ALIVE, game.getGameState()); // Draw claim invalid
|
||||
res = game.processString("e4");
|
||||
p = game.processString("e4");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(TextIO.UCIstringToMove("e2e4"), p.second);
|
||||
assertEquals(true, game.haveDrawOffer()); // Invalid claim converted to draw offer
|
||||
|
||||
String fen = "8/4k3/8/P7/8/8/8/1N2K2R w K - 99 83";
|
||||
game.setPos(TextIO.readFEN(fen));
|
||||
res = game.processString("draw 50");
|
||||
game.processString("draw 50");
|
||||
assertEquals(Game.GameState.ALIVE, game.getGameState()); // Draw claim invalid
|
||||
|
||||
game.setPos(TextIO.readFEN(fen));
|
||||
|
@ -163,8 +184,10 @@ public class GameTest extends TestCase {
|
|||
assertEquals(true, game.haveDrawOffer()); // Previous invalid claim converted to offer
|
||||
game.processString("draw 50");
|
||||
assertEquals(Game.GameState.ALIVE, game.getGameState()); // 50 move counter reset.
|
||||
res = game.processString("draw accept");
|
||||
p = game.processString("draw accept");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(null, p.second);
|
||||
assertEquals(Game.GameState.DRAW_AGREE, game.getGameState()); // Can accept previous implicit offer
|
||||
|
||||
fen = "3k4/R7/3K4/8/8/8/8/8 w - - 99 78";
|
||||
|
@ -301,12 +324,16 @@ public class GameTest extends TestCase {
|
|||
public void testProcessString() throws ChessParseError {
|
||||
Game game = new Game(null, new TimeControlData());
|
||||
assertEquals(TextIO.startPosFEN, TextIO.toFEN(game.currPos()));
|
||||
boolean res = game.processString("Nf3");
|
||||
Pair<Boolean,Move> p = game.processString("Nf3");
|
||||
boolean res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(TextIO.UCIstringToMove("g1f3"), p.second);
|
||||
assertEquals(1, game.currPos().halfMoveClock);
|
||||
assertEquals(1, game.currPos().fullMoveCounter);
|
||||
res = game.processString("d5");
|
||||
p = game.processString("d5");
|
||||
res = p.first;
|
||||
assertEquals(true, res);
|
||||
assertEquals(TextIO.UCIstringToMove("d7d5"), p.second);
|
||||
assertEquals(0, game.currPos().halfMoveClock);
|
||||
assertEquals(2, game.currPos().fullMoveCounter);
|
||||
|
||||
|
@ -336,12 +363,16 @@ public class GameTest extends TestCase {
|
|||
game.setPos(TextIO.readFEN(fen));
|
||||
assertEquals(pos, game.currPos());
|
||||
|
||||
res = game.processString("junk");
|
||||
p = game.processString("junk");
|
||||
res = p.first;
|
||||
assertEquals(false, res);
|
||||
assertEquals(null, p.second);
|
||||
|
||||
game.newGame();
|
||||
res = game.processString("e7e5");
|
||||
p = game.processString("e7e5");
|
||||
res = p.first;
|
||||
assertEquals(false, res);
|
||||
assertEquals(null, p.second);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
162
DroidFishTest/src/org/petero/droidfish/gamelogic/SpeechTest.java
Normal file
162
DroidFishTest/src/org/petero/droidfish/gamelogic/SpeechTest.java
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
DroidFish - An Android chess program.
|
||||
Copyright (C) 2016 Peter Österlund, peterosterlund2@gmail.com
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.petero.droidfish.gamelogic;
|
||||
|
||||
import org.petero.droidfish.Speech;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class SpeechTest extends TestCase {
|
||||
public SpeechTest() {
|
||||
}
|
||||
|
||||
public void testEnglish() {
|
||||
String lang = "en";
|
||||
{
|
||||
Game game = new Game(null, new TimeControlData());
|
||||
Pair<Boolean,Move> res = game.processString("e4");
|
||||
assertEquals("e4", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("d5");
|
||||
assertEquals("d5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("exd5");
|
||||
assertEquals("e takes d5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("Qxd5");
|
||||
assertEquals("Queen takes d5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("Ne2");
|
||||
assertEquals("Knight e2", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("Nf6");
|
||||
assertEquals("Knight f6", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("Nbc3");
|
||||
assertEquals("Knight b c3", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("e5");
|
||||
assertEquals("e5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("b4");
|
||||
assertEquals("b4", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("a5");
|
||||
assertEquals("a5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("a3");
|
||||
assertEquals("a3", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("axb4");
|
||||
assertEquals("ae takes b4", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("axb4");
|
||||
assertEquals("ae takes b4", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
}
|
||||
{
|
||||
Game game = new Game(null, new TimeControlData());
|
||||
Pair<Boolean,Move> res = game.processString("d4");
|
||||
assertEquals("d4", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("e5");
|
||||
assertEquals("e5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("dxe5");
|
||||
assertEquals("d take e5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("f6");
|
||||
assertEquals("f6", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("exf6");
|
||||
assertEquals("e takes f6", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("Bb4");
|
||||
assertEquals("Bishop b4. Check!", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("c3");
|
||||
assertEquals("c3", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("Ne7");
|
||||
assertEquals("Knight e7", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("cxb4");
|
||||
assertEquals("c takes b4", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("O-O");
|
||||
assertEquals("Short castle", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("fxg7");
|
||||
assertEquals("f takes g7", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("h6");
|
||||
assertEquals("h6", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("gxf8Q+");
|
||||
assertEquals("g takes f8 Queen. Check!", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("Kxf8");
|
||||
assertEquals("King takes f8", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("b5");
|
||||
assertEquals("b5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("a5");
|
||||
assertEquals("a5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("bxa6");
|
||||
assertEquals("b takes a6", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
}
|
||||
{
|
||||
Game game = new Game(null, new TimeControlData());
|
||||
Pair<Boolean,Move> res = game.processString("f4");
|
||||
assertEquals("f4", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("e5");
|
||||
assertEquals("e5", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("g4");
|
||||
assertEquals("g4", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
|
||||
res = game.processString("Qh4");
|
||||
assertEquals("Queen h4. Check mate!", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
}
|
||||
{
|
||||
Game game = new Game(null, new TimeControlData());
|
||||
playMoves(game, "d4 d5 Nc3 Nc6 Bf4 Bf5 Qd2 Qd7");
|
||||
Pair<Boolean,Move> res = game.processString("O-O-O");
|
||||
assertEquals("Long castle", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
playMoves(game, "Nxd4 Nxd5 Qxd5 Qxd4 Qxd4 Nf3 Qxd1 Kxd1");
|
||||
res = game.processString("O-O-O");
|
||||
assertEquals("Long castle. Check!", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
}
|
||||
{
|
||||
Game game = new Game(null, new TimeControlData());
|
||||
playMoves(game, "e4 e5 h3 Bb4 Ne2 Bc3");
|
||||
Pair<Boolean,Move> res = game.processString("Nexc3");
|
||||
assertEquals("Knight e takes c3", Speech.moveToText(game.prevPos(), res.second, lang));
|
||||
}
|
||||
}
|
||||
|
||||
private void playMoves(Game game, String moves) {
|
||||
for (String move : moves.split(" ")) {
|
||||
Pair<Boolean,Move> res = game.processString(move);
|
||||
assertTrue(res.first);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user