Package mines

Source Code of mines.MineSolverThread

/**
* Copyright (C) 2010, LGPL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* @author Matfyz, fyzmat@gmail.com
*/

package mines;

import com.trolltech.qt.QSignalEmitter;
import com.trolltech.qt.QSignalEmitter.Signal1;
import java.util.List;
import mines.MineSolver.ComputationAbortedException;
import mines.MineSolver.FIELD_SOLVE_RESULT;
import mines.MineSolver.MinesSolverInternalError;
import mines.MinefieldContainer.Coord;
import mines.MinesUtils.MineSweeperData;

/**
* Thread for making the solver computations. Started by a thread runner.
*/
public class MineSolverThread extends QSignalEmitter implements Runnable {

  /**
   * Mode for running the solver.
   */
  public enum MODE {
    /** The marked clear fields are revealed immedeately */
    SOLVE_AND_REVEAL,
    /** The solver only marks clear and mined fields. */
    SOLVE_ONLY
  }

  /** Identical reference as mines.MineSweeperLogic.mRealMinefield. */
  MinefieldContainer<GUI_FIELD> mRealMinefield = null;
  /** Identical reference as mines.MineSweeperLogic.mViewedMinefield. */
  MinefieldContainer<GUI_FIELD> mViewedMinefield = null;
  /** Identical reference as mines.MineSweeperLogic.mSolver. */
  MineSolver mSolver = null;

  /** Current way of solving the minefield*/
  MODE mMode = MODE.SOLVE_ONLY;

  /** Signals, that specified field should be revealed */
  public Signal1<Coord> mFieldRevealedSignal = new Signal1<Coord>();
  /** Signals, that specified field should be marked as clear */
  public Signal1<Coord> mFieldMarkClearSignal = new Signal1<Coord>();
  /** Signals, that specified field should be marked as clear */
  public Signal1<Coord> mFieldMarkMineSignal = new Signal1<Coord>();

  /**
   * Changes the working content of the thread.
   *
   * @param realMinefield Container of current minefield (uncovered fields).
   * @param viewedMinefield Container of current minefield (fields, which the user see).
   * @param solver The solver object.
   */
  public void setContent(MinefieldContainer<GUI_FIELD> realMinefield,
    MinefieldContainer<GUI_FIELD> viewedMinefield, MineSolver solver) {

    mRealMinefield = realMinefield;
    mViewedMinefield = viewedMinefield;
    mSolver = solver;
  }

  /**
   * Sets the mode of evaluating solver results.
   * @param mode Mode of the solver thread.
   */
  public void setMode(MODE mode) {
    mMode = mode;
  }

  /**
   * Main function of this thread. Runs the solver evaluation.
   */
  public void run() {
    try {
      runSolverTest();
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Saves current minefield to file for debugging purposes.
   * @param filePath Filename, where the minefield will be saved.
   */
  void saveCurrentMinefieldState(String filePath) {
    MineSweeperData data = new MineSweeperData();
    data.mRealContent = mRealMinefield;
    data.mViewedContent = mViewedMinefield;

    MinesUtils.saveMinefieldToFileSafely(data, filePath);
  }

  /**
   * Signals to gui thread, that some changes should be made on specified field,
   * and waits for response of GUI thread.
   *
   * @param signal Signal to be emitted.
   * @param argument Coordinates of field, which should be changed.
   */
  void signalToGUI(Signal1<Coord> signal, Coord argument) {
    try {
      synchronized(this) {
        signal.emit(argument);
        this.wait();
      }
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }   
  }

  /**
   * Runs the solver until the solver has some determinable field to mark.
   */
  void runSolverTest(){

    //mSolver.enableLogging(true);

    MinefieldContainer<SOLVER_FIELD> solverData =
        MinesUtils.convertGUIToSolverMinefield(mViewedMinefield);
    mSolver.setContent(solverData);

    // continue to run the solver until there has been some change
    while(true) {
      List<Coord> coveredCoords = mViewedMinefield.getAllFieldsIndexes(GUI_FIELD.COVERED_FLAG);

      boolean continueTesting = solveFields(coveredCoords);
      if(!continueTesting) {
        break;
      }
    }

    mSolver.enableLogging(false);
  }

  /**
   * Emits the signal, that specified covered field should be marked as mined.
   * @param coveredCoord Coordinates of field to mark.
   */
  void markMine(Coord coveredCoord) {
    GUI_FIELD realValue = mRealMinefield.get(coveredCoord);
    if (!realValue.equals(GUI_FIELD.MINE)) {
      throw new MinesSolverInternalError("Bad evaluation of mine "
          + " at coord " + coveredCoord);
    }

    signalToGUI(mFieldMarkMineSignal, coveredCoord);
  }

  /**
   * Emits the signal, that specified covered field should be marked as cleared.
   * @param coveredCoord Coordinates of field to mark.
   */
  void markClearField(Coord coveredCoord) {
    GUI_FIELD realValue = mRealMinefield.get(coveredCoord);
    if (realValue.equals(GUI_FIELD.MINE)) {
      throw new MinesSolverInternalError("Bad evaluation of clear "
          + " at coord " + coveredCoord);
    }

    signalToGUI(mFieldMarkClearSignal, coveredCoord);
  }

  /**
   * Emits the signal, that specified covered field should be revealed.
   * @param coveredCoord Coordinates of field to reveal.
   */
  void revealClearField(Coord coveredCoord) {
    GUI_FIELD realValue = mRealMinefield.get(coveredCoord);
    if (realValue.equals(GUI_FIELD.MINE)) {
      throw new MinesSolverInternalError("Bad evaluation of clear "
          + " at coord " + coveredCoord);
    }

    signalToGUI(mFieldRevealedSignal, coveredCoord);
  }

  /**
   * Decides, what to do with field, which has been determined as cleared.
   * @param coveredCoord Coordinates of field, which has been marked.
   */
  void handleClearField(Coord coveredCoord) {
    switch(mMode) {
      case SOLVE_ONLY:
        markClearField(coveredCoord);
      break;
     
      case SOLVE_AND_REVEAL:
        revealClearField(coveredCoord);
      break;
     
      default:
        throw new Error("Unexpected solver thread mode: " + mMode);
    }
  }

  /**
   * For each covered field asks the solver, if the field is unknown, mined or
   * numbered.
   *
   * @param coveredCoords All covered fields, which will be checked.
   * @return False, if the solver has not discovered something new or,
   * if the computation was aborted.
   */
  boolean solveFields(List<Coord> coveredCoords) {
    boolean continueTesting = false;

    try {
      for(Coord coveredCoord : coveredCoords) {
        FIELD_SOLVE_RESULT result = mSolver.solveOneField(coveredCoord);

        switch(result) {
          case UNKNOWN:
          break;

          case MUST_BE_MINE:
            markMine(coveredCoord);

            mSolver.findApparentFields();

            continueTesting = true;
          break;

          case CANNOT_BE_MINE:
            handleClearField(coveredCoord);

            mSolver.findApparentFields();

            continueTesting = true;
          break;

          default:
            throw new MinesSolverInternalError("Unexpected value " + result);
        }
      }
    } catch (ComputationAbortedException abortEx) {
      return false;
    } catch (MinesSolverInternalError internalEx) {
      internalEx.printStackTrace();
      saveCurrentMinefieldState("./corruptedMinefieldState.msd");

      return false;
    }

    return continueTesting;
  }
}
TOP

Related Classes of mines.MineSolverThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.