/* * Quackle -- Crossword game artificial intelligence and analysis tool * Copyright (C) 2005-2019 Jason Katz-Brown, John O'Laughlin, and John Fultz. * * 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 . */ #ifndef QUACKER_QUACKER_H #define QUACKER_QUACKER_H // #define ENABLE_GRAPHICAL_REPORT #include #include #include #include "oppothread.h" #include #include class QAction; class QActionGroup; class QComboBox; class QCheckBox; class QFrame; class QGroupBox; class QLineEdit; class QPushButton; class QSplitter; class QTabWidget; class QTimer; class QVBoxLayout; class OppoThreadProgressBar; namespace Quackle { class ComputerPlayer; class Game; class GamePosition; class History; class HistoryLocation; class Move; class Rack; } namespace QuackleIO { class Logania; } class BaseView; class HistoryView; class Letterbox; class ListerDialog; class QuackerSettings; class Settings; class SimViewer; class View; class TopLevel : public QMainWindow { Q_OBJECT public: TopLevel(QWidget *parent = 0); ~TopLevel(); void closeEvent(QCloseEvent *closeEvent); // returns text wrapped in an HTML tag to ensure dialog wrapping static QString dialogText(const QString &text); public slots: void open(); void newGame(); // like loadFile, but set the filename, initial directory, // and other things void openFile(const QString &filename); // actually loads the file void loadFile(const QString &filename); void save(); void saveAs(); void writeFile(const QString &filename); void generateList(); void letterbox(); void kibitz(); void kibitz(int numberOfPlays, Quackle::ComputerPlayer *computerPlayer = 0); void kibitzFifty(); void kibitzAll(); void kibitzAs(Quackle::ComputerPlayer *computerPlayer); void firstPosition(); void nextPosition(); void previousPosition(); void reportAs(Quackle::ComputerPlayer *computerPlayer); void htmlReport(); void graphicalReport(); void commitTopChoice(); void simulate(bool startSimulation); void simulateToggled(bool startSimulation); void clearSimulationResults(); void showAscii(); void writeAsciiToFile(const QString &text, const QString &filename); void copyToClipboard(const QString &text); void print(); void firstTimeRun(); void about(); void hints(); void showConfigDialog(); // set up our game object based on a shuffled playerList void initializeGame(const Quackle::PlayerList *players); // call timerControl, and tell user about it void pause(bool paused); protected slots: // final set up of initial data structures // and an example game void finishInitialization(); // say hi void introduceToUser(); // prepares current position and spawns computer player thread // if necessary then sends orders to update the UI void advanceGame(); // asks oppo thread to find best move void startOppoThread(); // called by oppo thread when it's done void computerPlayerDone(); // called by player thread when it's done void kibitzThreadFinished(); // called by a oppo/player thread when it has a status update void playerFractionDone(double fraction, OppoThread *thread); // update both positional and history views, // then wait for human to make a play void showToHuman(); // use this to control timer! void timerControl(bool paused); // commit candidate play then advance the game void commit(); // add a pass candidate void pass(); // handle an overdraw void overdraw(); void statusMessage(const QString &message); // set game's candidate to move and update views void setCandidateMove(const Quackle::Move *move, bool *carryOnPtr = nullptr); void removeCandidateMoves(const Quackle::MoveList *moves); // set current player's rack and update views void setRack(const Quackle::Rack &rack); // set current position's explanatory note void setNote(const UVString ¬e); // set history location to view void goToHistoryLocation(const Quackle::HistoryLocation *location); // stop simulation, opponenent thread, etc void stopEverything(); // update all views (usually because of a settings change) void updateAllViews(); // update *positional* views - emit positionChanged void updatePositionViews(); // updates move views from either simulation results if available // or kibitzed moves void updateMoveViews(); // update history views when a new position is added void updateHistoryViews(); void setCaption(const QString &text = QString()); void setModified(bool modified); // main timer void timeout(); // simulation timer void incrementSimulation(); void updateSimViews(); // simulator settings: void pliesSet(int plyIndex); void ignoreOpposChanged(); void updatePliesCombo(); void logfileEnabled(bool on); void logfileChanged(); void chooseLogfile(); void partialOppoRackEnabled(bool on); void partialOppoRackChanged(); void showSimulationDetails(); // Birthday void startBirthday(); void birthdayBash(); void birthdayGram(int index, bool on); signals: // emitted when views (eg board) should update based on the // current position (includes board information, current candidate play // that should be shown) void positionChanged(const Quackle::GamePosition *position); void movesChanged(const Quackle::MoveList *moves); // emitted when views of history must update void historyChanged(const Quackle::History &history); protected: Quackle::DataManager m_dataManager; Quackle::Game *m_game; Quackle::Simulator *m_simulator; private: void saveSettings(); void loadSettings(); // returns 0 for save, 1 for discard, 2 for cancel int askToSave(); // returns true if user wants to make play anyway bool askToCarryOn(const QString &text); // used to know when to update UI when performing heavy calculation bool m_initializationChuu; // are dictionaries etc properly set up? bool setupCheck(); // hook up signals and slots associated with a view void plugIntoBaseMatrix(BaseView *view); void plugIntoMatrix(View *view); void plugIntoPositionMatrix(View *view); void plugIntoMoveMatrix(View *view); void plugIntoHistoryMatrix(HistoryView *view); void parseCommandLineOptions(); bool isPlayerOnTurnComputer() const; bool isCommitAllowed() const; bool shouldOutcraftyCurrentPlayer() const; void startOutcraftyingCurrentPlayer(); void stopOutcraftyingCurrentPlayer(); // Used to sanitize a move for a player with unknown racks. // Changes exchanges to exchange tiles on the current rack. // If move is a place, changes current player's rack to something // that includes the used tiles. // Returns true if the validization was successful. bool validifyMove(Quackle::Move &move); void kibitzFinished(); OppoThreadProgressBar *createProgressBarForThread(OppoThread *thread); void removeProgressIndicators(); void removeProgressIndicator(OppoThread *thread); OppoThreadProgressBar *progressBarOfThread(OppoThread *thread); // generic game title QString gameTitle(); UVString m_firstPlayerName; QString playerString() const; QList m_oppoThreads; QList m_otherOppoThreads; QTimer *m_timer; QTimer *m_simulationTimer; QMap m_progressIndicators; View *m_brb; QSplitter *m_splitter; QVBoxLayout *m_leftSideLayout; enum TabIndex { HistoryTabIndex = 0, ChoicesTabIndex = 1, SettingsTabIndex = 2}; QTabWidget *m_tabWidget; HistoryView *m_history; HistoryView *m_dashboard; QWidget *m_choicesWidget; View *m_moveBox; View *m_noteEditor; QFrame *m_frameWidget; Settings *m_settings; ListerDialog *m_listerDialog; void updateListerDialogWithRack(); Letterbox *m_letterbox; QuackerSettings *m_quackerSettings; // encapsulated simulator settings widget QGroupBox *m_simulatorWidget; QPushButton *m_showDetailsButton; QLineEdit *m_logfileEdit; QGroupBox *m_logfileEnable; QPushButton *m_logfileChooser; QLineEdit *m_partialOppoRackEdit; QGroupBox *m_partialOppoRackEnable; QCheckBox *m_ignoreOpposCheck; static const int m_pliesToOffer = 6; QComboBox *m_pliesCombo; SimViewer *m_simViewer; void setLogfileEnabled(bool enabled); bool isLogfileEnabled() const; // the value of the file-choosing lineedit QString userSpecifiedLogfile() const; // what user specified, or empty string if logging disabled QString logfile() const; void setPartialOppoRackEnabled(bool enabled); bool isPartialOppoRackEnabled() const; // the value of the partial oppo rack-choosing lineedit QString userSpecifiedPartialOppoRack() const; // what user specified, or empty string if logging disabled QString partialOppoRack() const; int m_plies; // end encapsulation, hah QString m_filename; QuackleIO::Logania *m_logania; bool m_modified; QString m_ourCaption; QString getInitialDirectory() const; void setInitialDirectory(const QString &filename); QString m_initialDirectory; QString gameFileFilters() const; QString defaultGameFileFilter() const; QActionGroup *m_kibitzAsActions; QActionGroup *m_reportAsActions; QAction *m_htmlReportAction; QAction *m_showAsciiAction; QAction *m_generateAction; QAction *m_newAction; QAction *m_openAction; QAction *m_saveAction; QAction *m_saveAsAction; QAction *m_pauseAction; QAction *m_firstPositionAction; QAction *m_nextPositionAction; QAction *m_previousPositionAction; QAction *m_commitAction; QAction *m_passAction; QAction *m_overdrawAction; QAction *m_kibitzAction; QAction *m_kibitzFiftyAction; QAction *m_kibitzAllAction; QAction *m_commitTopChoiceAction; QAction *m_simulateAction; QAction *m_simulateClearAction; QAction *m_simulateDetailsAction; QAction *m_preferencesAction; #ifdef ENABLE_GRAPHICAL_REPORT QAction *m_graphicalReportAction; #endif // make sure moves in our simulator match those in current position void ensureUpToDateSimulatorMoveList(); void createMenu(); void createWidgets(); void switchToTab(TabIndex index); // Birthday QTimer *m_birthdayTimer; int m_birthdayIndex; }; class KibitzerListener : public QObject { Q_OBJECT public: KibitzerListener(Quackle::ComputerPlayer *computerPlayer, QObject *parent); public slots: void kibitzTriggered(); void reportTriggered(); signals: void kibitzAs(Quackle::ComputerPlayer *computerPlayer); void reportAs(Quackle::ComputerPlayer *computerPlayer); private: // returns true if the action should still be carried out despite slowness bool slownessCheck(); Quackle::ComputerPlayer *m_computerPlayer; bool m_slowPlayerWarningTriggered; }; #endif