[iagno] computer-player: fix cancel_move()
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [iagno] computer-player: fix cancel_move()
- Date: Wed, 24 Sep 2014 13:40:35 +0000 (UTC)
commit 0f7e313fb146a069579f40d404e1a539e27fec6b
Author: Michael Catanzaro <mcatanzaro gnome org>
Date: Sun Sep 21 15:57:02 2014 -0500
computer-player: fix cancel_move()
https://bugzilla.gnome.org/show_bug.cgi?id=736941
src/computer-player.vala | 52 +++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 49 insertions(+), 3 deletions(-)
---
diff --git a/src/computer-player.vala b/src/computer-player.vala
index e40b27a..b30b3e6 100644
--- a/src/computer-player.vala
+++ b/src/computer-player.vala
@@ -58,6 +58,28 @@ public class ComputerPlayer : Object
/* Source ID of a pending move timeout */
private uint pending_move_id = 0;
+ /* Indicates the results of the AI's search should be discarded.
+ * The mutex is only needed for its memory barrier. */
+ private bool _move_pending;
+ private RecMutex _move_pending_mutex;
+ private bool move_pending
+ {
+ get
+ {
+ _move_pending_mutex.lock ();
+ bool result = _move_pending;
+ _move_pending_mutex.unlock ();
+ return result;
+ }
+
+ set
+ {
+ _move_pending_mutex.lock ();
+ _move_pending = value;
+ _move_pending_mutex.unlock ();
+ }
+ }
+
public ComputerPlayer (Game game, int level = 1)
{
this.game = game;
@@ -73,6 +95,7 @@ public class ComputerPlayer : Object
}
}
+ /* For tests only. */
public void move ()
{
int x = 0;
@@ -88,8 +111,17 @@ public class ComputerPlayer : Object
int x = 0;
int y = 0;
+ while (move_pending)
+ {
+ /* We were called while a previous search was in progress.
+ * Wait for that to finish before continuing. */
+ Timeout.add (200, move_async.callback);
+ yield;
+ }
+
timer.start ();
new Thread<void *> ("AI thread", () => {
+ move_pending = true;
run_search (ref x, ref y);
move_async.callback ();
return null;
@@ -98,6 +130,9 @@ public class ComputerPlayer : Object
timer.stop ();
+ if (!move_pending)
+ return;
+
if (timer.elapsed () < delay_seconds)
{
pending_move_id = Timeout.add ((uint) ((delay_seconds - timer.elapsed ()) * 1000),
move_async.callback);
@@ -105,6 +140,7 @@ public class ComputerPlayer : Object
}
pending_move_id = 0;
+ move_pending = false;
/* complete_move() needs to be called on the UI thread. */
Idle.add (() => {
@@ -115,11 +151,19 @@ public class ComputerPlayer : Object
public void cancel_move ()
{
+ if (!move_pending)
+ return;
+
+ /* If AI thread has finished and its move is queued, unqueue it. */
if (pending_move_id != 0)
{
Source.remove (pending_move_id);
pending_move_id = 0;
}
+
+ /* If AI thread is running, this tells move_async() to ignore its result.
+ * If not, it's harmless, so it's safe to call cancel_move() on the human's turn. */
+ move_pending = false;
}
private void run_search (ref int x, ref int y)
@@ -148,7 +192,7 @@ public class ComputerPlayer : Object
}
- private static int search (Game g, Strategy strategy, int depth, int a, int b, ref int move_x, ref int
move_y)
+ private int search (Game g, Strategy strategy, int depth, int a, int b, ref int move_x, ref int move_y)
requires (a <= b)
{
/* End of the game, return a near-infinite evaluation */
@@ -159,8 +203,10 @@ public class ComputerPlayer : Object
return n_current_tiles > n_enemy_tiles ? POSITIVE_INFINITY - n_enemy_tiles : NEGATIVE_INFINITY +
n_current_tiles;
}
- /* End of the search, calculate how good a result this is */
- if (depth == 0)
+ /* End of the search, calculate how good a result this is.
+ * Checking move_pending here is optional. It helps avoid a long unnecessary search
+ * if the move has been cancelled, but is expensive because it requires taking a mutex. */
+ if (depth == 0 || !move_pending)
return calculate_heuristic (g, strategy);
/* Find all possible moves and sort from most new tiles to least new tiles */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]