⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 controller.cpp

📁 c+++ game uploading now
💻 CPP
字号:
/**
 @file 
 The code for the Controller object from the Model-View-Controller pattern,
 this is where all user input is accepted and interpreted. 
*/

#include "Controller.h"
#include "resource.h"
#include "lib/HelpProvider.h"
#include "lib/SaveFileDialog.h"
#include "lib/OpenFileDialog.h"
#include "lib/WinException.h"
#include "lib/MessageBox.h"
#include "AboutDialog.h"
#include "SearchOptionsDialog.h"

using namespace Win;
using namespace Othello;

//export from Main.cpp
extern HINSTANCE TheInstance;

Controller::Controller (HWND hwnd)
    : _hwnd(hwnd),
      _isUserTurn(false),
      _isUserBlack(false),
      _isGameStarted(false),
      _isGameOver(false),
      _minutesperside(DEF_MINUTES_PER_SIDE),
      _thinker(hwnd),
      _boardview(hwnd),
      _infoview(hwnd, _isUserTurn, _isGameStarted, _isUserBlack, _isGameOver),
      _timer(hwnd, 1) 
{
    // Attach icon to main dialog
    HICON hIcon=::LoadIcon(TheInstance, MAKEINTRESOURCE(IDI_ICON));
    ::SendMessage(hwnd, WM_SETICON, WPARAM(TRUE), LPARAM(hIcon));
    hIcon=::LoadIcon(TheInstance, MAKEINTRESOURCE(IDI_ICON));
    ::SendMessage(hwnd, WM_SETICON, WPARAM(FALSE), LPARAM(hIcon));


    _thinker.SetTotalTime(_minutesperside);
    _infoview.LookInside(_thinker);
    _infoview.UpdateBuffer();
    InvalidateViews(); 
    MenuStatusUpdate();
    //start think thread
    _thinker.Resume();
}


void Controller::OnCommand(int controlID, int command)
{
    switch (controlID)
    {
        case ID_GAME_NEW:       
            //start new game
            OnNew();
            break;
        case ID_GAME_ABORT:
            OnGameAbort();
            break;
        case ID_GAME_SAVEPOSITION:
            //save positon to a file
            OnSavePosition();
            break;
        case ID_GAME_SAVEGAME:
            OnSaveGame();
            break;
        case ID_GAME_LOADPOSITION:
            OnLoadPosition();
            break;
        case ID_GAME_EXIT:      
            //leave program
            OnExit();
            break;
        case ID_ACTIONS_HINT:
            //get a hint
            OnActionsHint();
            break;
        case ID_ACTIONS_SWITCHSIDES:
            OnActionsSwitchSides();
            break;
        case ID_ACTIONS_UNDO:
            OnActionsUndo();
            break;
        case ID_ACTIONS_FORCEMOVE:
            OnActionsForceMove();
            break;
        case ID_OPTIONS_SEARCH:
            OnOptionsSearch();
            break;
        case ID_HELP_CONTENTS:     
            OnHelpContents();
            break;
        case ID_HELP_ABOUT:
            OnHelpAbout();
            break;
    }    
}

Controller::MenuItem Controller::MenuStats[]=
{
    {ID_OPTIONS_SEARCH, &Controller::CanOptionsSearch},
    {ID_GAME_ABORT, &Controller::CanGameAbort},
    {ID_ACTIONS_HINT, &Controller::CanActionsHint},
    {ID_ACTIONS_UNDO, &Controller::CanActionsUndo},
    {ID_ACTIONS_SWITCHSIDES, &Controller::CanActionsSwitchSides},
    {ID_ACTIONS_FORCEMOVE, &Controller::CanActionsForceMove},
    {0, 0}
};

void Controller::OnLButtonDown(int x,int y)
{
    if(!_isGameStarted)
        return;
    if(_isUserTurn)
    {
        POINT point;
        point.x=x; point.y=y;
        HWND hwndBoard=_boardview.Hwnd();
        if(hwndBoard!=::ChildWindowFromPoint(_hwnd, point))
            return;

        ::MapWindowPoints(_hwnd, hwndBoard, &point,1);

        if(point.x<0) //patching a strange winbug.
            point.x=0; 
        if(point.y<0) //same thing.
            point.y=0; 
        _boardview.PixelToBoard(point);
        if(_boardview.PutPiece(point.x,point.y,_isUserBlack?black:white))
        {
            _thinker.AddMove(TTBoard::AntiPersil[(point.x-1)*8+point.y-1], _isUserBlack);
            if(!_boardview.IsStillUserTurn() && !_boardview.IsGameOver())
            {
                _boardview.SendTo(_thinker.newBoard);
                _infoview.UpdateBuffer();
                _isUserTurn=false;
                InvalidateViews(); 
                MenuStatusUpdate();
                _thinker.Go();
                return;
            }
            if(_boardview.IsStillUserTurn())
            {
                _infoview.UpdateBuffer();
                _isUserTurn=true; 
                InvalidateViews(); 
                MenuStatusUpdate();
                return;
            }
            if(_boardview.IsGameOver())
            {
                _thinker.Stop(); //!!!!!!!!!!!!!!!!!!!!1
                _isGameOver=true;
                _isGameStarted=false;
                _infoview.UpdateBuffer();
                MenuStatusUpdate();
                InvalidateViews(); 
                Win::MessageBox(_hwnd,"Game Over", "Shylock");
                _timer.Kill(); 
                _thinker.ResetGame();
                return;
            }
        }
    }
}

void Controller::OnTimer(int id)
{
    _timer.Kill();
    _thinker.CheckTime();
    //TODO change this protocol
    _infoview.LookInside(_thinker);
    _infoview.UpdateBuffer();
    _infoview.InvalidateOnParent(); //::InvalidateRect(_hwnd, 0, FALSE);
    _timer.Set(1000);
}

void Controller::OnUpdateView()
{
    //HEY I'm making more than one move
    BeepAndFlashWindow();    
    _boardview.Get(_thinker.newBoard);
    _infoview.UpdateBuffer();
    InvalidateViews(); 
}

void Controller::OnCalcDone()
{
    _boardview.Get(_thinker.newBoard);
    _isUserTurn=true;
    BeepAndFlashWindow();
    MenuStatusUpdate();
    if(_boardview.IsGameOver())
    {
        _thinker.Stop();
        _isGameStarted=false;
        _isGameOver=true; 
        _infoview.UpdateBuffer();
        MenuStatusUpdate();
        _timer.Kill();
        _thinker.ResetGame();
        InvalidateViews(); 
        Win::MessageBox(_hwnd, "Game Over", "Shylock");
        return;
    }
    _infoview.UpdateBuffer();
    InvalidateViews(); 
    //say: GO!
    //NOTE disabled for debuging purposes
    //_thinker.Go();
}

void Controller::OnNew()
{
    if(_isGameStarted)
    {
        Win::MessageBox mbox(_hwnd, "Do you wish to abort current game?",
                        "ShyLock", MB_YESNO|MB_DEFBUTTON2);
        if(mbox.Status()==IDNO)
            return;
    }
    _thinker.Stop();
    _timer.Kill(); //??? what happens if it is not started?
    _boardview.InitBoards();
    _infoview.Clean();
    _thinker.SetTotalTime(_minutesperside);

    InvalidateViews(); //entire window

    Win::MessageBox mbox(_hwnd, "Do you wish to play Black?",
                    "ShyLock",MB_YESNO);
    _isUserBlack=(IDYES==mbox.Status());
    _isUserTurn=_isUserBlack;
    _isGameStarted=true;
    _isGameOver=false;
    MenuStatusUpdate();
    _timer.Set(1000);
    _thinker.ResetGame();
    //say: GO!
    if(!_isUserTurn)  
        _thinker.Go();
}


void Controller::OnLoadPosition()
{
    OpenFileDialog opener(_hwnd);
    PSTR filename=opener.GetFileName();
    if(filename==NULL)
        return;

    Board tmp;
    if(!_boardview.LoadFromFile(filename,tmp))
    {
        Win::MessageBox(_hwnd, "Syntax failure");
        return;
    }

    if(_isGameStarted)
    {
        Win::MessageBox mbox(_hwnd, "Do you wish to abort current game?",
                        "ShyLock", MB_YESNO|MB_DEFBUTTON2);
        if(IDNO==mbox.Status())
            return;
    }

    _isGameOver=false;

    _timer.Kill(); //??? what happens if it is not started?
    _thinker.Stop();
    _boardview.Get(tmp);
    _boardview.SendTo(_thinker.newBoard);

    InvalidateViews(); //entire window
    
    Win::MessageBox mbox(_hwnd, "Do you wish to play Black?",
                    "ShyLock", MB_YESNO);

    _isUserBlack=(IDYES==mbox.Status());
    
    _isUserTurn=(_isUserBlack==tmp.isblacksturn);
    _timer.Set(1000);
    _isGameStarted=true;
    MenuStatusUpdate();

    //say: GO!
    if(!_isUserTurn)
        _thinker.Go();
    _infoview.Clean();
    return;
}


void Controller::OnActionsSwitchSides()
{
    _timer.Kill();
    //TODO add _thinker.Stop here, background thinking is done
    _isUserBlack=!_isUserBlack;
    _isUserTurn=!_isUserTurn;
    _thinker.Stop();
    _boardview.SendTo(_thinker.newBoard);
    InvalidateViews(); 
    MenuStatusUpdate();
    _timer.Set(1000);
    //say: GO!
    if(!_isUserTurn) 
        _thinker.Go();
}


void Controller::MenuStatusUpdate()
{
    HMENU  myMenu=::GetMenu(_hwnd);
    for(int i=0; MenuStats[i].CanBeEnabled!=0; i++)
    {
        bool (Controller::*pmem)() const = MenuStats[i].CanBeEnabled; 
        if( (this->*pmem)() )
            ::EnableMenuItem(myMenu, MenuStats[i].id, MF_ENABLED);
        else
            ::EnableMenuItem(myMenu, MenuStats[i].id, MF_GRAYED);
    }
}

void Controller::OnPaint()
{
    PaintCanvas canvasAll(_hwnd);
    if(_boardview.IsInsideRect(canvasAll.PaintRect()))
    {
        PaintCanvas canvasBoard(_boardview.Hwnd());
        _boardview.Paint(canvasBoard);
    }
    if(_infoview.IsInsideRect(canvasAll.PaintRect()))
    {
        PaintCanvas canvasInfo(_infoview.Hwnd());
        _infoview.Paint(canvasInfo);
    }
}

bool Controller::CanOptionsSearch() const
{
    return !_isGameStarted;
}

bool Controller::CanGameAbort() const
{
    return _isGameStarted;
}

bool Controller::CanActionsHint() const
{
    return _isGameStarted && _isUserTurn;
}

bool Controller::CanActionsUndo() const
{
    return _isGameStarted;
}

bool Controller::CanActionsSwitchSides() const
{
    return _isGameStarted && _isUserTurn;
}

bool Controller::CanActionsForceMove() const
{
    return _isGameStarted && !_isUserTurn;
}

void Controller::OnHelpContents()
{
    HelpProvider::Open(_hwnd, "Usage.htm");
}

void Controller::OnSaveGame()
{
    SaveFileDialog saver(_hwnd,"gam");
    PSTR filename=saver.GetFileName();
    if(filename!=NULL)
        _infoview.SaveGameToFile(filename);
}

void Controller::OnSavePosition()
{
    SaveFileDialog saver(_hwnd,"pos");
    PSTR filename=saver.GetFileName();
    if(filename!=NULL)
        _boardview.SaveToFile(filename);
}

void Controller::OnOptionsSearch()
{    
    SearchOptionsDialog dialog(TheInstance, _hwnd, 
                               _thinker.TTLogSize(),
                               _minutesperside);

    //if OK was pressed and there was a change
    if(dialog.IsOK() && 
        (dialog.LogSize()!=_thinker.TTLogSize() ||
         dialog.Minutes()!=_minutesperside))
    {
        if(dialog.LogSize()<17)
        {
            Win::MessageBox(_hwnd, "Less then 1 Mb is by far not enough, I'll just ignore that.",
                            "Why are you so cheap?", MB_ICONQUESTION|MB_OK);
            return;
        }
        if(dialog.Minutes()<1)
        {
            Win::MessageBox(_hwnd, "Less then 1 minute is by far not fair, since there is no time limit for your thinking. I'll just ignore that.",
                           "Why are you so cheap?", MB_ICONQUESTION|MB_OK);
            return;
        }
        _thinker.TTChangeSize(dialog.LogSize());
        _minutesperside=dialog.Minutes();
        _thinker.SetTotalTime(_minutesperside);
    }      
}


void Controller::OnHelpAbout()            
{
    //display ABOUT dialogbox            
    AboutDialog dialog(TheInstance,_hwnd);
}

void Controller::OnGameAbort()
{
    assert(_isGameStarted);
    Win::MessageBox mbox(_hwnd, "Abort this game.",
                   "Confirm:", MB_YESNO|MB_ICONINFORMATION);

    if(IDNO==mbox.Status())
        return;
    _timer.Kill(); //??? what happens if it is not started?
    _thinker.Stop();
    _isGameStarted=false;
    MenuStatusUpdate();
}

void Controller::OnExit()
{
    //No "save xxx" nag message, simply exit
    ::PostMessage(_hwnd, WM_CLOSE, 0, 0);
}


void Controller::InvalidateViews(BOOL berase)
{
    _boardview.InvalidateOnParent(berase);
    _infoview.InvalidateOnParent(berase);
}


void Controller::BeepAndFlashWindow()
{
    ::MessageBeep(0xffffffff);
    ::FlashWindow(_hwnd, FALSE);
}

void Controller::OnActionsHint()
{
    assert(_isUserTurn);
    //TODO add _thinker.Stop here, background thinking is done
    int bmove=_thinker.Hint();
    if(bmove!=-1)
        _boardview.Hinted(bmove);
    else
    {
        Win::MessageBox(_hwnd, "No hint avaible!", "Sory ...");
    }   
}

void Controller::OnActionsUndo()
{
    Win::MessageBox(_hwnd, "Not yet implemented");
}


void Controller::OnActionsForceMove()
{
    //Win::MessageBox(_hwnd, "Not yet implemented");
    _thinker.Force_Stop();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -