- total_moves = w*h*n*n*2;
- for (i = 0; i < total_moves; i++) {
- int x, y;
-
- x = random_upto(rs, w - n + 1);
- y = random_upto(rs, h - n + 1);
- do_rotate(grid, w, h, n, params->orientable,
- x, y, 1 + random_upto(rs, 3));
-
- /*
- * Optionally one more move in case the entire grid has
- * happened to come out solved.
- */
- if (i == total_moves - 1 && grid_complete(grid, wh,
- params->orientable))
- i--;
- }
+ total_moves = params->movetarget;
+ if (!total_moves)
+ total_moves = w*h*n*n*2 + random_upto(rs, 2);
+
+ do {
+ int oldx = -1, oldy = -1, oldr = -1;
+
+ for (i = 0; i < total_moves; i++) {
+ int x, y, r;
+
+ do {
+ x = random_upto(rs, w - n + 1);
+ y = random_upto(rs, h - n + 1);
+ r = 1 + 2 * random_upto(rs, 2);
+ } while (x == oldx && y == oldy && (oldr == 0 || r == oldr));
+
+ do_rotate(grid, w, h, n, params->orientable,
+ x, y, r);
+
+ /*
+ * Prevent immediate reversal of a previous move, or
+ * execution of three consecutive identical moves
+ * adding up to a single inverse move. One exception is
+ * when we only _have_ one x,y setting.
+ */
+ if (w != n || h != n) {
+ if (oldx == x && oldy == y)
+ oldr = 0; /* now avoid _any_ move in this x,y */
+ else
+ oldr = -r & 3; /* only prohibit the exact inverse */
+ oldx = x;
+ oldy = y;
+ }
+ }
+ } while (grid_complete(grid, wh, params->orientable));