Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) Maziak source code (version 2.0)

 

Maziak version 2.0 source code.

 

Operating system: Ubuntu 10.04 LTS Lucid Lynx

IDE: Qt Creator 2.0.0

Project type: GUI application

Compiler: G++ 4.4.1

Libraries used:

 

 

 

 

 

Qt project file

 

#-------------------------------------------------
#
# Project created by QtCreator 2010-07-23T19:17:35
#
#-------------------------------------------------

QT += core gui

TARGET = GameMaziak
TEMPLATE = app


SOURCES += main.cpp\
formmenu.cpp \
formmain.cpp \
formgameover.cpp \
formgamewon.cpp \
formabout.cpp \
forminstructions.cpp \
formwhatsnew.cpp

HEADERS += \
formmenu.h \
formmain.h \
formgameover.h \
formgamewon.h \
formabout.h \
forminstructions.h \
formwhatsnew.h

FORMS += \
formmenu.ui \
formmain.ui \
formgameover.ui \
formgamewon.ui \
formabout.ui \
forminstructions.ui \
formwhatsnew.ui

RESOURCES += \
resources.qrc

 

 

 

 

 

formabout.cpp

 

#include <boost/shared_ptr.hpp>

#include "formabout.h"
#include "formwhatsnew.h"
#include "ui_formabout.h"

FormAbout::FormAbout(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::FormAbout)
{
  ui->setupUi(this);

  QObject::connect(
    ui->button_whats_new,SIGNAL(clicked()),
    this,SLOT(onWhatsNew()));
}

FormAbout::~FormAbout()
{
  delete ui;
}

void FormAbout::changeEvent(QEvent *e)
{
  QDialog::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
  default:
    break;
  }
}

void FormAbout::onWhatsNew()
{
  boost::shared_ptr<FormWhatsNew> f(new FormWhatsNew);
  f->exec(); //Show the pop-up modally
}

 

 

 

 

 

formabout.h

 

#ifndef FORMABOUT_H
#define FORMABOUT_H

#include <QDialog>

namespace Ui {
  class FormAbout;
}

class FormAbout : public QDialog
{
  Q_OBJECT

public:
  explicit FormAbout(QWidget *parent = 0);
  ~FormAbout();

protected:
  void changeEvent(QEvent *e);

private:
  Ui::FormAbout *ui;

private slots:
  void onWhatsNew();
};

#endif // FORMABOUT_H

 

 

 

 

 

formgameover.cpp

 

#include <cassert>

#include <boost/timer.hpp>

#include <QPainter>
#include <QPaintEvent>
#include <QTimer>

#include "formgameover.h"
#include "ui_formgameover.h"

FormGameOver::FormGameOver(QWidget *parent) :
  QDialog(parent),
  ui(new Ui::FormGameOver),
  m_timer(new QTimer),
  m_allow_close(false)
{
  ui->setupUi(this);
  m_timer->setInterval(2500);
  QObject::connect(m_timer.get(),SIGNAL(timeout()),this,SLOT(onTimer()));
  m_timer->start();
}

FormGameOver::~FormGameOver()
{
  delete ui;
}

void FormGameOver::changeEvent(QEvent *e)
{
  QWidget::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
  default:
    break;
  }
}

void FormGameOver::onTimer()
{
  m_allow_close = true;
  m_timer->stop();
}

void FormGameOver::paintEvent(QPaintEvent*)
{
  QPainter painter(this);
  {
    //Top
    QPixmap pixmap(":/images/GameOver.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_top->geometry(),pixmap);
  }
  {
    //Center
    QPixmap pixmap(":/images/Rip.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_center->geometry(),pixmap);
  }
  {
    //Bottom
    QPixmap pixmap(":/images/GameOver.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_bottom->geometry(),pixmap);
  }
}

void FormGameOver::mousePressEvent(QMouseEvent*)
{
  if (m_allow_close) close();
}

void FormGameOver::keyPressEvent(QKeyEvent*)
{
  if (m_allow_close) close();
}



 

 

 

 

 

formgameover.h

 

#ifndef FORMGAMEOVER_H
#define FORMGAMEOVER_H

#include <boost/shared_ptr.hpp>
#include <QDialog>

struct QTimer;

namespace Ui {
  class FormGameOver;
}

class FormGameOver : public QDialog
{
  Q_OBJECT

public:
  explicit FormGameOver(QWidget *parent = 0);
  ~FormGameOver();

protected:
  void changeEvent(QEvent *e);
  void paintEvent(QPaintEvent*);
  void mousePressEvent(QMouseEvent*);
  void keyPressEvent(QKeyEvent*);

private:
  Ui::FormGameOver *ui;
  boost::shared_ptr<QTimer> m_timer;
  bool m_allow_close;

  private slots:
  void onTimer();

};

#endif // FORMGAMEOVER_H

 

 

 

 

 

formgamewon.cpp

 

#include <cassert>
#include <iostream>

#include <boost/timer.hpp>

#include <QPainter>
#include <QPaintEvent>
#include <QTimer>

#include "formgamewon.h"
#include "ui_formgamewon.h"

FormGameWon::FormGameWon(QWidget *parent) :
  QDialog(parent),
  ui(new Ui::FormGameWon),
  m_timer(new QTimer),
  m_allow_close(false)
{
  ui->setupUi(this);

  m_timer->setInterval(2500);
  QObject::connect(m_timer.get(),SIGNAL(timeout()),this,SLOT(onTimer()));
  m_timer->start();
}

FormGameWon::~FormGameWon()
{
  delete ui;
}

void FormGameWon::changeEvent(QEvent *e)
{
  QWidget::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
  default:
    break;
  }
}

void FormGameWon::onTimer()
{
  m_allow_close = true;
  m_timer->stop();
}

void FormGameWon::paintEvent(QPaintEvent*)
{
  QPainter painter(this);
  {
    //Top
    QPixmap pixmap(":/images/Congratulations.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_top->geometry(),pixmap);
  }
  {
    //Center
    QPixmap pixmap(":/images/PlayerWon1.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_center->geometry(),pixmap);
  }
  {
    //Bottom
    QPixmap pixmap(":/images/Congratulations.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_bottom->geometry(),pixmap);
  }
}

void FormGameWon::mousePressEvent(QMouseEvent*)
{
  if (m_allow_close) close();
}

void FormGameWon::keyPressEvent(QKeyEvent*)
{
  if (m_allow_close) close();
}


 

 

 

 

 

formgamewon.h

 

#ifndef FORMGAMEWON_H
#define FORMGAMEWON_H

#include <boost/shared_ptr.hpp>
#include <QDialog>

struct QTimer;

namespace Ui {
  class FormGameWon;
}

class FormGameWon : public QDialog
{
  Q_OBJECT

public:
  explicit FormGameWon(QWidget *parent = 0);
  ~FormGameWon();

protected:
  void changeEvent(QEvent *e);
  void paintEvent(QPaintEvent*);
  void mousePressEvent(QMouseEvent*);
  void keyPressEvent(QKeyEvent*);

private:
  Ui::FormGameWon *ui;
  boost::shared_ptr<QTimer> m_timer;
  bool m_allow_close;

  private slots:
  void onTimer();
};

#endif // FORMGAMEWON_H

 

 

 

 

 

forminstructions.cpp

 

#include "forminstructions.h"
#include "ui_forminstructions.h"

FormInstructions::FormInstructions(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::FormInstructions)
{
    ui->setupUi(this);
}

FormInstructions::~FormInstructions()
{
    delete ui;
}

void FormInstructions::changeEvent(QEvent *e)
{
    QDialog::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

 

 

 

 

 

forminstructions.h

 

#ifndef FORMINSTRUCTIONS_H
#define FORMINSTRUCTIONS_H

#include <QDialog>

namespace Ui {
    class FormInstructions;
}

class FormInstructions : public QDialog
{
    Q_OBJECT

public:
    explicit FormInstructions(QWidget *parent = 0);
    ~FormInstructions();

protected:
    void changeEvent(QEvent *e);

private:
    Ui::FormInstructions *ui;
};

#endif // FORMINSTRUCTIONS_H

 

 

 

 

 

formmain.cpp

 

#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <stdexcept>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>

#include <QDesktopWidget>
#include <QKeyEvent>
#include <QPainter>
#include <QTimer>
#include "formgameover.h"
#include "formgamewon.h"
#include "formmain.h"
#include "ui_formmain.h"

FormMain::FormMain(QWidget *parent, const int maze_size) :
    QDialog(parent,Qt::Window),
    ui(new Ui::FormMain),
    //Floor
    m_pixmap_empty(new QPixmap(":/images/Empty.png")),
    m_pixmap_wall(new QPixmap(":/images/Wall.png")),
    m_pixmap_path(new QPixmap(":/images/Path.png")),
    m_pixmap_transparent(new QPixmap(":/images/Transparent.png")),
    //Player sprites
    m_pixmap_player_look_down(new QPixmap(":/images/PlayerLookDown.png")),
    m_pixmap_player_look_down_sword(new QPixmap(":/images/PlayerLookDownSword.png")),
    m_pixmap_player_look_left(new QPixmap(":/images/PlayerLookLeft.png")),
    m_pixmap_player_look_left_sword(new QPixmap(":/images/PlayerLookLeftSword.png")),
    m_pixmap_player_look_right(new QPixmap(":/images/PlayerLookRight.png")),
    m_pixmap_player_look_right_sword(new QPixmap(":/images/PlayerLookRightSword.png")),
    m_pixmap_player_look_up(new QPixmap(":/images/PlayerLookUp.png")),
    m_pixmap_player_look_up_sword(new QPixmap(":/images/PlayerLookUpSword.png")),
    m_pixmap_player_walk_left1(new QPixmap(":/images/PlayerWalkLeft1.png")),
    m_pixmap_player_walk_left2(new QPixmap(":/images/PlayerWalkLeft2.png")),
    m_pixmap_player_walk_left_sword1(new QPixmap(":/images/PlayerWalkLeftSword1.png")),
    m_pixmap_player_walk_left_sword2(new QPixmap(":/images/PlayerWalkLeftSword2.png")),
    m_pixmap_player_walk_right1(new QPixmap(":/images/PlayerWalkRight1.png")),
    m_pixmap_player_walk_right2(new QPixmap(":/images/PlayerWalkRight2.png")),
    m_pixmap_player_walk_right_sword1(new QPixmap(":/images/PlayerWalkRightSword1.png")),
    m_pixmap_player_walk_right_sword2(new QPixmap(":/images/PlayerWalkRightSword2.png")),
    m_pixmap_player_walk_down1(new QPixmap(":/images/PlayerWalkDown1.png")),
    m_pixmap_player_walk_down2(new QPixmap(":/images/PlayerWalkDown2.png")),
    m_pixmap_player_walk_down_sword1(new QPixmap(":/images/PlayerWalkDownSword1.png")),
    m_pixmap_player_walk_down_sword2(new QPixmap(":/images/PlayerWalkDownSword2.png")),
    m_pixmap_player_walk_up1(new QPixmap(":/images/PlayerWalkUp1.png")),
    m_pixmap_player_walk_up2(new QPixmap(":/images/PlayerWalkUp2.png")),
    m_pixmap_player_walk_up_sword1(new QPixmap(":/images/PlayerWalkUpSword1.png")),
    m_pixmap_player_walk_up_sword2(new QPixmap(":/images/PlayerWalkUpSword2.png")),
    m_pixmap_player_won1(new QPixmap(":/images/PlayerWon1.png")),
    m_pixmap_player_won2(new QPixmap(":/images/PlayerWon2.png")),
    //Fighting sprites
    m_pixmap_fight_sword1(new QPixmap(":/images/FightSword1.png")),
    m_pixmap_fight_no_sword1(new QPixmap(":/images/FightNoSword1.png")),
    m_pixmap_fight2(new QPixmap(":/images/Fight2.png")),
    m_pixmap_fight3(new QPixmap(":/images/Fight3.png")),
    m_pixmap_fight4(new QPixmap(":/images/Fight4.png")),
    m_pixmap_fight_won1(new QPixmap(":/images/FightWon1.png")),
    m_pixmap_fight_won2(new QPixmap(":/images/FightWon2.png")),
    m_pixmap_fight_lost1(new QPixmap(":/images/FightLost1.png")),
    m_pixmap_fight_lost2(new QPixmap(":/images/FightLost2.png")),
    //Others
    m_pixmap_enemy1(new QPixmap(":/images/Enemy1.png")),
    m_pixmap_enemy2(new QPixmap(":/images/Enemy2.png")),
    m_pixmap_prisoner1(new QPixmap(":/images/Prisoner1.png")),
    m_pixmap_prisoner2(new QPixmap(":/images/Prisoner2.png")),
    m_pixmap_sword(new QPixmap(":/images/Sword.png")),
    m_pixmap_exit(new QPixmap(":/images/Exit.png")),
    m_timer_press_key(new QTimer),
    m_timer_enemy(new QTimer),
    m_timer_show_solution(new QTimer),
    mX(-1),
    mY(-1),
    mViewWidth(9),
    mViewHeight(9),
    mHasSword(true),
    mFighting(0),
    mCheat(false),
    mShowSolution(false),
    mDirection(pdDown),
    mMoveNow(none)
{
  ui->setupUi(this);
  assert(m_pixmap_empty);
  assert(!m_pixmap_empty->isNull());
  assert(m_pixmap_wall);
  assert(!m_pixmap_wall->isNull());
  assert(m_pixmap_path);
  assert(!m_pixmap_path->isNull());
  assert(!m_pixmap_player_look_down->isNull());
  assert(!m_pixmap_player_look_down_sword->isNull());
  assert(!m_pixmap_player_look_left->isNull());
  assert(!m_pixmap_player_look_left_sword->isNull());
  assert(!m_pixmap_player_look_right->isNull());
  assert(!m_pixmap_player_look_right_sword->isNull());
  assert(!m_pixmap_player_look_up->isNull());
  assert(!m_pixmap_player_look_up_sword->isNull());
  assert(!m_pixmap_player_walk_left1->isNull());
  assert(!m_pixmap_player_walk_left2->isNull());
  assert(!m_pixmap_player_walk_left_sword1->isNull());
  assert(!m_pixmap_player_walk_left_sword2->isNull());
  assert(!m_pixmap_player_walk_right1->isNull());
  assert(!m_pixmap_player_walk_right2->isNull());
  assert(!m_pixmap_player_walk_right_sword1->isNull());
  assert(!m_pixmap_player_walk_right_sword2->isNull());
  assert(!m_pixmap_player_walk_down1->isNull());
  assert(!m_pixmap_player_walk_down2->isNull());
  assert(!m_pixmap_player_walk_down_sword1->isNull());
  assert(!m_pixmap_player_walk_down_sword2->isNull());
  assert(!m_pixmap_player_walk_up1->isNull());
  assert(!m_pixmap_player_walk_up2->isNull());
  assert(!m_pixmap_player_walk_up_sword1->isNull());
  assert(!m_pixmap_player_walk_up_sword2->isNull());
  assert(!m_pixmap_player_won1->isNull());
  assert(!m_pixmap_player_won2->isNull());

  assert(maze_size && "Maze size must be 7 + (4 * n) for n e [0,->>");

  m_timer_press_key->setInterval(100);
  m_timer_enemy->setInterval(1000);
  m_timer_show_solution->setInterval(5000);

  QObject::connect(m_timer_press_key.get(),SIGNAL(timeout()),
    this,SLOT(onTimerPressKey()));
  QObject::connect(m_timer_enemy.get(),SIGNAL(timeout()),
    this,SLOT(onTimerEnemy()));
  QObject::connect(m_timer_show_solution.get(),SIGNAL(timeout()),
    this,SLOT(onTimerShowSolution()));

  createMaze(maze_size);
  assert(IsSquare(mMaze));
  assert(IsSquare(mIntMaze));
  assert(mSolution.empty() || IsSquare(mSolution));
  assert(IsSquare(mDistances));

  m_timer_press_key->start();
  m_timer_enemy->start();

  //Put the dialog in the screen center at 75% of fullscreen size
  const QRect screen = QApplication::desktop()->screenGeometry();
  this->setGeometry(0,0,screen.width() * 75 / 100,screen.height() * 75 / 100);
  this->move( screen.center() - this->rect().center() );
}

FormMain::~FormMain()
{
  delete ui;
}

void FormMain::changeEvent(QEvent *e)
{
  QWidget::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
  default:
    break;
  }
}

void FormMain::resizeEvent(QResizeEvent*)
{
  this->repaint();
}

void FormMain::keyPressEvent(QKeyEvent* e)
{
  if (mFighting > 0) repaint();

  mKeys.insert(e->key());

  switch (e->key())
  {
    case Qt::Key_Left : mKeys.erase(Qt::Key_Right); break;
    case Qt::Key_Right: mKeys.erase(Qt::Key_Left); break;
    case Qt::Key_Up   : mKeys.erase(Qt::Key_Down); break;
    case Qt::Key_Down : mKeys.erase(Qt::Key_Up); break;
    case Qt::Key_F1   : gameOver(); close(); break;
    case Qt::Key_F2   : gameWon(); close(); break;
    case Qt::Key_Escape: close(); break;
  }
}

void FormMain::keyReleaseEvent(QKeyEvent * e)
{
  mKeys.erase(e->key());
}

void FormMain::onTimerPressKey()
{
  if (mFighting > 0) return;
  if (mKeys.empty()) { mMoveNow = none; }

  BOOST_FOREACH(WORD key, mKeys)
  {
    //Check the keys pressed
    switch (key)
    {
      case Qt::Key_Left:
        mDirection = pdLeft;
        if (!CanMoveTo(mMaze,mX-1,mY,mHasSword,mShowSolution))
        {
          mMoveNow = none;
          continue;
        }
        mMoveNow = (mMoveNow == left1 ? left2 : left1);
        --mX;
        break;
      case Qt::Key_Right:
        mDirection = pdRight;
        if (!CanMoveTo(mMaze,mX+1,mY,mHasSword,mShowSolution))
        {
          mMoveNow = none;
          continue;
        }
        mMoveNow = (mMoveNow == right1 ? right2 : right1);
        ++mX;
        break;
      case Qt::Key_Up:
        mDirection = pdUp;
        if (!CanMoveTo(mMaze,mX,mY-1,mHasSword,mShowSolution))
        {
          mMoveNow = none;
          continue;
        }
        mMoveNow = (mMoveNow == up1 ? up2 : up1);
        --mY;
        break;
      case Qt::Key_Down:
        mDirection = pdDown;
        if (!CanMoveTo(mMaze,mX,mY+1,mHasSword,mShowSolution))
        {
          mMoveNow = none;
          continue;
        }
        mMoveNow = (mMoveNow == down1 ? down2 : down1);
        ++mY;
        break;
      default:
        mMoveNow = none;
        continue;
    }
    //Draw the screen
    repaint();
  }
}

void FormMain::onTimerEnemy()
{
  //Move them
  const int minx = std::max(0,mX - mViewWidth );
  const int miny = std::max(0,mY - mViewHeight);
  const int maxy = std::min(static_cast<int>(mMaze.size()),mY + mViewHeight);
  const int maxx = std::min(static_cast<int>(mMaze[mY].size()),mX + mViewWidth);
  assert(miny >= 0);
  assert(miny <= static_cast<int>(mMaze.size()));
  assert(maxy >= 0);
  assert(maxy <= static_cast<int>(mMaze.size()));
  assert(minx >= 0);
  assert(minx <= static_cast<int>(mMaze[mY].size()));
  assert(maxx >= 0);
  assert(maxx <= static_cast<int>(mMaze[mY].size()));
  assert(miny <= maxy);
  assert(minx <= maxx);
  for (int y=miny; y!=maxy; ++y)
  {
    assert( y >= 0);
    assert( y < static_cast<int>(mMaze.size()));
    for (int x=minx; x!=maxx; ++x)
    {
      //msEnemy1 changes to msEnemy2
      //Only msEnemy2 moves, after moving turning to msEnemy1
      assert( x >= 0);
      assert( x < static_cast<int>(mMaze[y].size()));
      const MazeSquare s = mMaze[y][x];

      if (s == msEnemy1)
      {
        //msEnemy1 changes to msEnemy2
        mMaze[y][x] = msEnemy2;
        continue;
      }
      else if (s == msEnemy2)
      {
        //msEnemy 2 tries to walk
        std::vector<std::pair<int,int> > moves;
        if (y > mY && y >        1 && mMaze[y-1][x  ] == msEmpty) moves.push_back(std::make_pair(x,y-1));
        if (x < mX && x < maxx - 1 && mMaze[y  ][x+1] == msEmpty) moves.push_back(std::make_pair(x+1,y));
        if (y < mY && y < maxy - 1 && mMaze[y+1][x  ] == msEmpty) moves.push_back(std::make_pair(x,y+1));
        if (x > mX && x >        1 && mMaze[y  ][x-1] == msEmpty) moves.push_back(std::make_pair(x-1,y));
        const int nMoves = static_cast<int>(moves.size());
        if (nMoves == 1)
        {
          mMaze[y][x] = msEnemy1;
          std::swap(mMaze[y][x],mMaze[moves[0].second][moves[0].first]);
        }
        else if (nMoves > 1)
        {
          assert(nMoves == 2);
          mMaze[y][x] = msEnemy1;
          const int moveIndex = (std::rand() >> 4) % nMoves;
          std::swap(mMaze[y][x],mMaze[moves[moveIndex].second][moves[moveIndex].first]);
        }
      }
      else if (s==msPrisoner1)
      {
        //Animate prisoners
        mMaze[y][x] = msPrisoner2;
      }
      else if (s==msPrisoner2)
      {
        //Animate prisoners
        mMaze[y][x] = msPrisoner1;
      }
    }
  }
  repaint();
}

void FormMain::onTimerShowSolution()
{
  mShowSolution = false;
  m_timer_show_solution->stop();
}

void FormMain::paintEvent(QPaintEvent *)
{
  const int block_width  = 1 + ((ui->widget->width()  - 4) / mViewWidth);
  const int block_height = 1 + ((ui->widget->height() - 4) / mViewHeight);

  if (mFighting > 0)
  {
    ++mFighting;
    if (mFighting == 13)
    {
      if (!mHasSword)
      {
        gameOver();
        this->close();
      }
      mFighting = 0;
      mHasSword = false;
    }
  }

  //Player-environment interactions
  QPainter painter(this);
  assert(painter.isActive());

  //Clean painter
  {
    const QPixmap temp(":/images/Empty.png");
    assert(!temp.isNull());
    painter.drawPixmap(ui->widget->rect(),temp);
  }


  assert(mY >= 0);
  assert(mY < static_cast<int>(mMaze.size()));
  assert(mX >= 0);
  assert(mX < static_cast<int>(mMaze[mY].size()));
  switch (mMaze[mY][mX])
  {

    case msEmpty:
      break;
    case msWall:
      assert(!"Should not get here");
      throw std::logic_error("Player cannot be in wall");
    case msEnemy1: case msEnemy2:
      mFighting = 1;
      mMaze[mY][mX] = msEmpty;
      break;
    case msPrisoner1: case msPrisoner2:
      mMaze[mY][mX] = msEmpty;
      mSolution = GetDistancesPath(mDistances,mX,mY);
      assert(IsSquare(mSolution));
      mShowSolution = true;
      m_timer_show_solution->start();
      break;
    case msSword:
      mMaze[mY][mX] = msEmpty;
      mHasSword = true;
      break;
    case msExit:
    {
      gameWon();
      this->close();
      break;
    }
    default:
      assert(!"Should not get here");
      break;
  }

  //Draw maze
  {
    for (int y=0; y!=mViewHeight; ++y)
    {
      for (int x=0; x!=mViewWidth; ++x)
      {
        //xVector and yVector are the indices in the non-visual maze 2D std::vector
        const int xVector = mX - (mViewWidth  / 2) + x;
        const int yVector = mY - (mViewHeight / 2) + y;
        //Draw the floor tile
        const QPixmap& pixmap_floor = GetPixmapFloor(xVector,yVector);
        assert(!pixmap_floor.isNull());
        painter.drawPixmap(
          (x * block_width )+0,
          (y * block_height)+0,
          block_width,
          block_height,
          pixmap_floor);
        //Draw what's moving or standing on the floor
        const QPixmap& pixmap_above_floor = GetPixmapAboveFloor(xVector,yVector);
        assert(!pixmap_above_floor.isNull());
        painter.drawPixmap(
          (x * block_width )+0,
          (y * block_height)+0,
          block_width,
          block_height,
          pixmap_above_floor);
      }
    }
  }

  //Draw player
  {
    const QPixmap& player = GetPixmapPlayer(mDirection,mMoveNow);
    assert(!player.isNull());
    painter.drawPixmap(
      ((mViewWidth  / 2) * block_width )+0,
      ((mViewHeight / 2) * block_height)+0,
       block_width,
       block_height,
       player);
  }
}

void FormMain::gameOver()
{
  m_timer_press_key->stop();
  m_timer_enemy->stop();
  m_timer_show_solution->stop();
  this->hide();
  boost::scoped_ptr<FormGameOver> f(new FormGameOver(0));
  f->exec();
}

void FormMain::gameWon()
{
  m_timer_press_key->stop();
  m_timer_enemy->stop();
  m_timer_show_solution->stop();
  this->hide();
  boost::scoped_ptr<FormGameWon> f(new FormGameWon);
  this->hide();
  f->exec();
}


const QPixmap& FormMain::GetPixmapFloor(const int x, const int y) const
{
  const int sz = static_cast<int>(mMaze.size());
  assert(sz > 0);
  assert(sz == static_cast<int>(mMaze[0].size()));
  assert(mShowSolution == false ||  mSolution.size() == mMaze.size());

  //QPixmap pixmap;
  if ( x < 0
    || y < 0
    || x >= sz
    || y >= sz)
  {
    return *(m_pixmap_wall.get());
  }
  else if (mShowSolution
    && mSolution[y][x] == 1
    && ( mMaze[y][x] == msEmpty
      || mMaze[y][x] == msEnemy1
      || mMaze[y][x] == msEnemy2)
    )
  {
    return *(m_pixmap_path.get());
  }
  return *(m_pixmap_empty.get());
}

const QPixmap& FormMain::GetPixmapAboveFloor(const int x, const int y) const
{
  const int sz = static_cast<int>(mMaze.size());
  if ( x < 0
    || y < 0
    || x >= sz
    || y >= sz)
  {
    return *m_pixmap_wall.get();
  }
  //What else here?
  switch(mMaze[y][x])
  {
    case msEmpty     : return *m_pixmap_transparent.get();
    case msWall      : return *m_pixmap_wall.get();
    case msEnemy1    : return *m_pixmap_enemy1.get();
    case msEnemy2    : return *m_pixmap_enemy2.get();
    case msPrisoner1 : return *m_pixmap_prisoner1.get();
    case msPrisoner2 : return *m_pixmap_prisoner2.get();
    case msSword     : return *m_pixmap_sword.get();
    case msExit      : return *m_pixmap_exit.get();
    default:
      assert(!"Should not get here");
      throw std::logic_error("Unexpected MazeSquare at mMaze");
  }
}

const QPixmap& FormMain::GetPixmapPlayer(
  const PlayerDirection direction,
  const PlayerMove moveNow) const
{
  switch (mFighting)
  {
    case  0: break;
    case  1: return (mHasSword ? *m_pixmap_fight_sword1.get() : *m_pixmap_fight_no_sword1.get());
    case  2: return *m_pixmap_fight2.get();
    case  3: return *m_pixmap_fight3.get();
    case  4: return *m_pixmap_fight4.get();
    case  5: return (mHasSword ? *m_pixmap_fight_sword1.get() : *m_pixmap_fight_no_sword1.get());
    case  6: return *m_pixmap_fight2.get();
    case  7: return *m_pixmap_fight3.get();
    case  8: return *m_pixmap_fight4.get();
    case  9: return (mHasSword ? *m_pixmap_fight_won1.get() : *m_pixmap_fight_lost1.get());
    case 10: return (mHasSword ? *m_pixmap_fight_won2.get() : *m_pixmap_fight_lost2.get());
    case 11: return (mHasSword ? *m_pixmap_fight_won1.get() : *m_pixmap_fight_lost1.get());
    case 12: return (mHasSword ? *m_pixmap_fight_won2.get() : *m_pixmap_fight_lost2.get());
  }

  switch (direction)
  {
  case pdUp:
    {
      switch (moveNow)
      {
      case none: return (mHasSword ? *m_pixmap_player_look_up_sword.get() : *m_pixmap_player_look_up.get());
      case up1:  return (mHasSword ? *m_pixmap_player_walk_up_sword1.get() : *m_pixmap_player_walk_up1.get());
      case up2:  return (mHasSword ? *m_pixmap_player_walk_up_sword2.get() : *m_pixmap_player_walk_up2.get());
      default:
        assert("!Should not get here");
        throw std::logic_error("Unsupported PlayerMove mMoveNow for mDirection == up");
      }
    }
    //break; Unreachable
  case pdRight:
    {
      switch (moveNow)
      {
      case none:   return (mHasSword ? *m_pixmap_player_look_right_sword.get() : *m_pixmap_player_look_right.get());
      case right1: return (mHasSword ? *m_pixmap_player_walk_right_sword1.get() : *m_pixmap_player_walk_right1.get());
      case right2: return (mHasSword ? *m_pixmap_player_walk_right_sword2.get() : *m_pixmap_player_walk_right2.get());
      default:
        assert("!Should not get here");
        throw std::logic_error("Unsupported PlayerMove mMoveNow for mDirection == right");
      }
    }
    //break; Unreachable
  case pdDown:
    {
      switch (moveNow)
      {
      case none:  return (mHasSword ? *m_pixmap_player_look_down_sword.get() : *m_pixmap_player_look_down.get());
      case down1: return (mHasSword ? *m_pixmap_player_walk_down_sword1.get() : *m_pixmap_player_walk_down1.get());
      case down2: return (mHasSword ? *m_pixmap_player_walk_down_sword2.get() : *m_pixmap_player_walk_down2.get());
      default:
        assert("!Should not get here");
        throw std::logic_error("Unsupported PlayerMove mMoveNow for mDirection == down");
      }
    }
    //break; Unreachable
  case pdLeft:
    {
      switch (moveNow)
      {
      case none:  return (mHasSword ? *m_pixmap_player_look_left_sword.get() : *m_pixmap_player_look_left.get());
      case left1: return (mHasSword ? *m_pixmap_player_walk_left_sword1.get() : *m_pixmap_player_walk_left1.get());
      case left2: return (mHasSword ? *m_pixmap_player_walk_left_sword2.get() : *m_pixmap_player_walk_left2.get());
      default:
        assert("!Should not get here");
        throw std::logic_error("Unsupported PlayerMove mMoveNow for mDirection == left");
      }
    }
    //break; Unreachable
  default:
    assert("!Should not get here");
    throw std::logic_error("Unsupported PlayerDirection");
  }
  //Unreachable
}

void FormMain::createMaze(const int sz)
{
  mIntMaze = ::CreateMaze(sz);
  mMaze = ConvertMatrix<int,MazeSquare>(mIntMaze);

  {
    std::vector<std::pair<int,int> > deadEnds = GetShuffledDeadEnds(mIntMaze);
    const int nDeadEnds = deadEnds.size();
    assert(nDeadEnds >= 2);
    const int nSwords    = (nDeadEnds - 2) / 3;
    const int nPrisoners = (nDeadEnds - 2) / 10;
    const int nEnemies   = (nDeadEnds - 2) / 4;

    //Set a minimum distance for the player to travel
    while (1)
    {
      const double x1 = static_cast<double>(deadEnds[0].first );
      const double y1 = static_cast<double>(deadEnds[0].second);
      const double x2 = static_cast<double>(deadEnds[1].first );
      const double y2 = static_cast<double>(deadEnds[1].second);
      const double a = x1 - x2;
      const double b = y1 - y2;
      const double minDist = 0.75 * static_cast<double>(sz);
      if (std::sqrt( (a * a) + (b * b) ) > minDist)
      {
        break;
      }
      else
      {
        std::swap(deadEnds[0],deadEnds[std::rand() % nDeadEnds]);
        std::swap(deadEnds[1],deadEnds[std::rand() % nDeadEnds]);
      }
    }

    mX = deadEnds[0].first;
    mY = deadEnds[0].second;
    assert(mMaze[deadEnds[0].second][deadEnds[0].first] == msEmpty);
    const int exitX = deadEnds[1].first;
    const int exitY = deadEnds[1].second;
    assert(mMaze[exitY][exitX] == msEmpty);
    mDistances = GetMazeDistances(mIntMaze,exitX,exitY);
    mMaze[deadEnds[1].second][deadEnds[1].first] = msExit;

    std::vector<std::pair<int,int> >::const_iterator deadEndIterator = deadEnds.begin() + 2;

    {
      //Place swords in maze, only in dead ends
      for (int i=0; i!=nSwords; ++i)
      {
        assert(deadEndIterator != deadEnds.end());
        const int x = (*deadEndIterator).first;
        const int y = (*deadEndIterator).second;
        assert(x!=mX || y!=mY);
        assert(mMaze[y][x] == msEmpty);
        mMaze[y][x] = msSword;
        ++deadEndIterator;
      }
      //Place prisoners in maze, only in dead ends
      for (int i=0; i!=nPrisoners; ++i)
      {
        assert(deadEndIterator != deadEnds.end());
        const int x = (*deadEndIterator).first;
        const int y = (*deadEndIterator).second;
        assert(x!=mX || y!=mY);
        assert(mMaze[y][x] == msEmpty);
        mMaze[y][x] = msPrisoner1;
        ++deadEndIterator;
      }

      for (int i=0; i!=nEnemies; ++i)
      {
        assert(deadEndIterator != deadEnds.end());
        const int x = (*deadEndIterator).first;
        const int y = (*deadEndIterator).second;
        assert(mMaze[y][x] == msEmpty);
        mMaze[y][x] = msEnemy1;
        ++deadEndIterator;
      }
    }
  }
}

//Adapted from http://www.richelbilderbeek.nl/CppIsSquare.htm
bool IsSquare(const std::vector<std::vector<FormMain::MazeSquare> >& v)
{
  assert(!v.empty());
  BOOST_FOREACH(std::vector<FormMain::MazeSquare> row, v)
  {
    if (row.size()!=v.size()) return false;
  }
  return true;
}

//Adapted from http://www.richelbilderbeek.nl/CppIsSquare.htm
bool IsSquare(const std::vector<std::vector<int> >& v)
{
  assert(!v.empty());
  BOOST_FOREACH(std::vector<int> row, v)
  {
    if (row.size()!=v.size()) return false;
  }
  return true;
}

//Creates a maze
// 0 : path
// 1 : wall
//From http://www.richelbilderbeek.nl/CppCreateMaze.htm
std::vector<std::vector<int> > CreateMaze(const int sz)
{
  //Assume correct size dimensions
  assert( sz > 4 && sz % 4 == 3
    && "Size must be 3 + (n * 4) for n > 0");

  //Start with a wall-only maze
  std::vector<std::vector<int> > maze(sz, std::vector<int>(sz,1));

  //Prepare maze, remove paths
  // XXXXXXX 1111111
  // X X X X 1212121
  // XXXXXXX 1111111
  // X XOX X -> 1210121
  // XXXXXXX 1111111
  // X X X X 1212121
  // XXXXXXX 1111111

  //Draw open spaces
  for (int y=1; y<sz; y+=2)
  {
    for (int x=1; x<sz; x+=2)
    {
      maze[y][x] = 2; //2: unexplored
    }
  }

  const int mid = sz/2;

  maze[mid][mid] = 0;

  std::vector<std::pair<int,int> > v;
  v.push_back(std::make_pair(mid,mid));
  while (!v.empty())
  {
    //Set a random explorer square at the back
    std::swap(v.back(),v[ std::rand() % static_cast<int>(v.size())]);
    //Check possible adjacent squares
    const int x = v.back().first;
    const int y = v.back().second;
    std::vector<std::pair<int,int> > next;
    if (x > 0 + 2 && maze[y][x-2] == 2) next.push_back(std::make_pair(x-2,y));
    if (y > 0 + 2 && maze[y-2][x] == 2) next.push_back(std::make_pair(x,y-2));
    if (x < sz - 2 && maze[y][x+2] == 2) next.push_back(std::make_pair(x+2,y));
    if (y < sz - 2 && maze[y+2][x] == 2) next.push_back(std::make_pair(x,y+2));
    //Dead end?
    if (next.empty())
    {
      v.pop_back();
      continue;
    }
    //Select a random next adjacent square
    const int nextIndex = (std::rand() >> 4) % static_cast<int>(next.size());
    const int nextX = next[nextIndex].first;
    const int nextY = next[nextIndex].second;
    //Clear next square
    maze[nextY][nextX] = 0;
    //Clear path towards next square
    maze[(y + nextY)/2][(x + nextX)/2] = 0;
    //Add next square to stack
    v.push_back(std::make_pair(nextX,nextY));
  }
  return maze;
}

//From http://www.richelbilderbeek.nl/GetMazeDistances.htm
std::vector<std::vector<int> > GetMazeDistances(
  const std::vector<std::vector<int> >& maze,
  const int x,
  const int y)
{
  //Assume maze is square
  assert(maze[0].size() == maze.size());
  assert(maze[y][x] == 0); //Assume starting point is no wall

  const int size = maze.size();
  const int area = size * size;
  const int maxDistance = area;
  std::vector<std::vector<int> > distances(size, std::vector<int>(size,maxDistance));
  {
    //Calculate the distances
    int distance = 0;
    distances[y][x] = 0; //Set final point
    std::vector< std::pair<int,int> > found;
    found.push_back(std::make_pair(x,y));

    while(found.empty() == false)
    {
      ++distance;
      std::vector< std::pair<int,int> > newFound;

      const std::vector< std::pair<int,int> >::iterator j = found.end();
      for (std::vector< std::pair<int,int> >::iterator i = found.begin(); i!=j; ++i)
      {
        const int x = (*i).first;
        const int y = (*i).second;

        if ( maze[y-1][x] == 0                 //No wall
          && distances[y-1][x] == maxDistance) //Not already in solution
        {
          distances[y-1][x] = distance;
          newFound.push_back(std::make_pair(x,y-1));
        }
        if ( maze[y+1][x] == 0                 //No wall
          && distances[y+1][x] == maxDistance) //Not already in solution
        {
          distances[y+1][x] = distance;
          newFound.push_back(std::make_pair(x,y+1));
        }

        if ( maze[y][x+1] == 0                 //No wall
          && distances[y][x+1] == maxDistance) //Not already in solution
        {
          distances[y][x+1] = distance;
          newFound.push_back(std::make_pair(x+1,y));
        }

        if ( maze[y][x-1] == 0                 //No wall
          && distances[y][x-1] == maxDistance) //Not already in solution
        {
          distances[y][x-1] = distance;
          newFound.push_back(std::make_pair(x-1,y));
        }

      }
      found = newFound;
    }
  }
  return distances;
}

const std::vector<std::pair<int,int> > GetShuffledDeadEnds(
    const std::vector<std::vector<int> >& intMaze)
{
  std::vector<std::pair<int,int> > deadEnds = GetDeadEnds(intMaze);
  std::random_shuffle(deadEnds.begin(), deadEnds.end());
  return deadEnds;
}

#include <vector>

//From http://www.richelbilderbeek.nl/CppGetDeadEnds.htm
std::vector<std::pair<int,int> > GetDeadEnds(const std::vector<std::vector<int> >& maze)
{
  const int size = maze.size();

  std::vector<std::pair<int,int> > deadEnds;

  for (int y=1; y!=size-1; ++y)
  {
    for (int x=1; x!=size-1; ++x)
    {
      if (maze[y][x] != 0) continue; //Continue if here is a wall
      const int nWalls
        = (maze[y+1][x  ] == 1 ? 1 : 0)
        + (maze[y-1][x  ] == 1 ? 1 : 0)
        + (maze[y  ][x+1] == 1 ? 1 : 0)
        + (maze[y  ][x-1] == 1 ? 1 : 0);
      if (nWalls == 3) deadEnds.push_back(std::make_pair(x,y));

    }
  }
  return deadEnds;
}

//From http://www.richelbilderbeek.nl/GetDistancesPath.htm
std::vector<std::vector<int> > GetDistancesPath(
  const std::vector<std::vector<int> >& distances,
  const int playerX,
  const int playerY)
{
  const int size = distances.size();

  std::vector<std::vector<int> > solution(size, std::vector<int>(size,0));
  {
    int x = playerX;
    int y = playerY;
    int distance = distances[y][x] - 1;
    while (distance >= 0)
    {
      //We must be where we are now
      solution[y][x] = 1;
      if ( x!=0      && distances[y][x-1] == distance ) { --x; --distance; continue; }
      if ( x!=size-1 && distances[y][x+1] == distance ) { ++x; --distance; continue; }
      if ( y!=0      && distances[y-1][x] == distance ) { --y; --distance; continue; }
      if ( y!=size-1 && distances[y+1][x] == distance ) { ++y; --distance; continue; }
    }
  }
  return solution;
}

bool CanMoveTo(
  const std::vector<std::vector<FormMain::MazeSquare> >& maze,
  const int x, const int y,
  const bool hasSword,
  const bool showSolution)
{
  //Bump into edge
  if (x < 0) return false;
  if (y < 0) return false;
  const int maxy = static_cast<int>(maze.size());
  if (y >= maxy) return false;
  if (x >= static_cast<int>(maze[y].size())) return false;
  const FormMain::MazeSquare s = maze[y][x];
  //Bump into wall
  if (s == FormMain::msWall) return false;
  //Bump into sword
  if (s == FormMain::msSword && hasSword) return false;
  //Bump into prisoner
  if (showSolution
    && (s == FormMain::msPrisoner1
     || s == FormMain::msPrisoner2) ) return false;
  //Bump into empty/enemy/exit, so player can move there
  return true;
}

 

 

 

 

 

formmain.h

 

#ifndef FORMMAIN_H
#define FORMMAIN_H

#include <cassert>
#include <set>
#include <list>
#include <vector>

#include <boost/shared_ptr.hpp>

#include <QDialog>


struct QPixmap;
struct QTimer;

namespace Ui {
  class FormMain;
}

class FormMain : public QDialog
{
  Q_OBJECT


public:
  enum PlayerDirection { pdLeft, pdRight, pdUp, pdDown };
  enum PlayerMove { none, left1, left2, right1, right2, up1, up2, down1, down2 };
  enum MazeSquare { msEmpty, msWall, msEnemy1, msEnemy2, msPrisoner1, msPrisoner2, msSword, msExit };

  explicit FormMain(QWidget *parent = 0, const int maze_size = 0);

  ~FormMain();

protected:
  void changeEvent(QEvent *e);

private:
  Ui::FormMain *ui;
  //Floor sprites
  const boost::shared_ptr<const QPixmap> m_pixmap_empty;
  const boost::shared_ptr<const QPixmap> m_pixmap_wall;
  const boost::shared_ptr<const QPixmap> m_pixmap_path;
  const boost::shared_ptr<const QPixmap> m_pixmap_transparent;
  //Player sprites
  const boost::shared_ptr<const QPixmap> m_pixmap_player_look_down;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_look_down_sword;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_look_left;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_look_left_sword;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_look_right;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_look_right_sword;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_look_up;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_look_up_sword;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_left1;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_left2;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_left_sword1;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_left_sword2;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_right1;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_right2;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_right_sword1;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_right_sword2;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_down1;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_down2;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_down_sword1;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_down_sword2;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_up1;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_up2;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_up_sword1;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_walk_up_sword2;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_won1;
  const boost::shared_ptr<const QPixmap> m_pixmap_player_won2;
  //Fighting sprites
  const boost::shared_ptr<const QPixmap> m_pixmap_fight_sword1;
  const boost::shared_ptr<const QPixmap> m_pixmap_fight_no_sword1;
  const boost::shared_ptr<const QPixmap> m_pixmap_fight2;
  const boost::shared_ptr<const QPixmap> m_pixmap_fight3;
  const boost::shared_ptr<const QPixmap> m_pixmap_fight4;
  const boost::shared_ptr<const QPixmap> m_pixmap_fight_won1;
  const boost::shared_ptr<const QPixmap> m_pixmap_fight_won2;
  const boost::shared_ptr<const QPixmap> m_pixmap_fight_lost1;
  const boost::shared_ptr<const QPixmap> m_pixmap_fight_lost2;
  //Non-player sprites
  const boost::shared_ptr<const QPixmap> m_pixmap_enemy1;
  const boost::shared_ptr<const QPixmap> m_pixmap_enemy2;
  const boost::shared_ptr<const QPixmap> m_pixmap_prisoner1;
  const boost::shared_ptr<const QPixmap> m_pixmap_prisoner2;
  const boost::shared_ptr<const QPixmap> m_pixmap_sword;
  const boost::shared_ptr<const QPixmap> m_pixmap_exit;
  //Timers
  const boost::shared_ptr<QTimer> m_timer_press_key;
  const boost::shared_ptr<QTimer> m_timer_enemy;
  const boost::shared_ptr<QTimer> m_timer_show_solution;

  int mX;
  int mY;
  const int mViewWidth;
  const int mViewHeight;
  bool mHasSword;
  int mFighting;
  bool mCheat;
  bool mShowSolution;
  PlayerDirection mDirection;
  PlayerMove mMoveNow;
  typedef unsigned int WORD;
  std::set<WORD> mKeys;
  std::vector<std::vector<int> > mSolution;
  std::vector<std::vector<int> > mIntMaze;
  std::vector<std::vector<MazeSquare> > mMaze;
  std::vector<std::vector<int> > mDistances;

  void createMaze(const int sz);
  void gameOver();
  void gameWon();
  const QPixmap& GetPixmapFloor(const int x, const int) const;
  const QPixmap& GetPixmapAboveFloor(const int x, const int) const;
  const QPixmap& GetPixmapPlayer(
      const PlayerDirection direction,
      const PlayerMove moveNow) const;

  //Events
  void resizeEvent(QResizeEvent*);
  void keyPressEvent(QKeyEvent * e);
  void keyReleaseEvent(QKeyEvent * e);
  void paintEvent(QPaintEvent * event);

private slots:
  void onTimerPressKey();
  void onTimerEnemy();
  void onTimerShowSolution();

};



template <class Source, class Target>
    const std::vector<std::vector<Target> > ConvertMatrix(
        const std::vector<std::vector<Source> >& v)
{
  const int maxy = static_cast<int>(v.size());
  assert(maxy>0);
  const int maxx = static_cast<int>(v[0].size());
  std::vector<std::vector<Target> > t(maxy,std::vector<Target>(maxx));
  for (int y=0; y!=maxy; ++y)
  {
    for (int x=0; x!=maxx; ++x)
    {
      t[y][x] = static_cast<Target>(v[y][x]);
    }
  }
  return t;
}

const std::vector<std::pair<int,int> > GetShuffledDeadEnds(
    const std::vector<std::vector<int> >& intMaze);

const std::vector<std::pair<int,int> > GetShuffledNonDeadEnds(
    const std::vector<std::vector<int> >& intMaze);

bool CanMoveTo(
    const std::vector<std::vector<FormMain::MazeSquare> >& maze,
    const int x, const int y,
    const bool hasSword,
    const bool showSolution);


//From http://www.richelbilderbeek.nl/CppCreateMaze.htm
std::vector<std::vector<int> > CreateMaze(const int sz);

//From http://www.richelbilderbeek.nl/CppGetDeadEnds.htm
std::vector<std::pair<int,int> > GetDeadEnds(const std::vector<std::vector<int> >& maze);

//From http://www.richelbilderbeek.nl/GetDistancesPath.htm
std::vector<std::vector<int> > GetDistancesPath(
  const std::vector<std::vector<int> >& distances,
  const int playerX,
  const int playerY);

//From http://www.richelbilderbeek.nl/CppGetMazeDistances.htm
std::vector<std::vector<int> > GetMazeDistances(
    const std::vector<std::vector<int> >& maze,
    const int x,
    const int y);

const std::vector<std::pair<int,int> > GetShuffledDeadEnds(
    const std::vector<std::vector<int> >& intMaze);


bool IsSquare(const std::vector<std::vector<FormMain::MazeSquare> >& v);
bool IsSquare(const std::vector<std::vector<int> >& v);

#endif // FORMMAIN_H

 

 

 

 

 

formmenu.cpp

 

#include <cassert>
#include <iostream>
#include <stdexcept>

#include <boost/scoped_ptr.hpp>

#include <QDesktopWidget>
#include <QDialog>
#include <QKeyEvent>
#include <QPainter>
#include <QMouseEvent>

#include "formabout.h"
#include "forminstructions.h"
#include "formmain.h"
#include "formmenu.h"
#include "ui_formmenu.h"

FormMenu::FormMenu(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::FormMenu),
    m_difficulty(easy)
{
  ui->setupUi(this);

  //Put the dialog in the screen's center
  const QRect screen = QApplication::desktop()->screenGeometry();
  this->move( screen.center() - this->rect().center() );
}

FormMenu::~FormMenu()
{
  delete ui;
}

void FormMenu::changeEvent(QEvent *e)
{
  QWidget::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
  default:
    break;
  }
}

void FormMenu::mousePressEvent(QMouseEvent * event)
{
  if (ui->widget_easy->geometry().contains(
    event->x(), event->y()))
  {
    m_difficulty = easy;
    repaint();
    return;
  }
  if (ui->widget_medium->geometry().contains(
    event->x(), event->y()))
  {
    m_difficulty = medium;
    repaint();
    return;
  }
  if (ui->widget_hard->geometry().contains(
    event->x(), event->y()))
  {
    m_difficulty = hard;
    repaint();
    return;
  }
  if (ui->widget_start->geometry().contains(
    event->x(), event->y()))
  {
    onStart(); return;
  }
  if (ui->widget_instructions->geometry().contains(
    event->x(), event->y()))
  {
    onInstructions();
    return;
  }
  if (ui->widget_about->geometry().contains(
    event->x(), event->y()))
  {
    onAbout();
    return;
  }
  if (ui->widget_quit->geometry().contains(
    event->x(), event->y()))
  {
    close();
  }
}

void FormMenu::keyPressEvent(QKeyEvent * event)
{
  switch (event->key())
  {
    case Qt::Key_Up: case Qt::Key_Left:
    {
      switch (m_difficulty)
      {
        case easy: return;
        case medium: m_difficulty = easy; repaint(); return;
        case hard: m_difficulty = medium; repaint(); return;
        default: assert(!"Should not get here");
      }
    }
    case Qt::Key_Down: case Qt::Key_Right:
    {
      switch (m_difficulty)
      {
        case easy: m_difficulty = medium; repaint(); return;
        case medium: m_difficulty = hard; repaint(); return;
        case hard: return;
        default: assert(!"Should not get here");
      }
    }
    case Qt::Key_S: onStart(); break;
    case Qt::Key_I: onInstructions(); break;
    case Qt::Key_A: onAbout(); break;
    case Qt::Key_Q: close(); break;
    default:
      break;
  }
}

void FormMenu::paintEvent(QPaintEvent*)
{
  QPainter painter(this);
  {
    //Top left
    QPixmap pixmap;
    switch (m_difficulty)
    {
      case easy:
        pixmap = QPixmap(":/images/PlayerWon1.png");
        break;
      case medium:
        pixmap = QPixmap(":/images/PlayerLookDown.png");
        break;
      case hard:
        pixmap = QPixmap(":/images/PlayerScared.png");
        break;
      default:
        assert(!"Should not get here");
    }
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_top_left->geometry(),pixmap);
  }
  {
    //Top right
    QPixmap pixmap;
    switch (m_difficulty)
    {
      case easy:
        pixmap = QPixmap(":/images/Fight2.png");
        break;
      case medium:
        pixmap = QPixmap(":/images/Fight3.png");
        break;
      case hard:
        pixmap = QPixmap(":/images/Fight4.png");
        break;
      default:
        assert(!"Should not get here");
    }
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_top_right->geometry(),pixmap);
  }
  {
    //Easy
    QPixmap pixmap(m_difficulty == easy
      ? ":/images/Easy_selected.png"
      : ":/images/Easy_not_selected.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_easy->geometry(),pixmap);
  }
  {
    //Medium
    QPixmap pixmap(m_difficulty == medium
      ? ":/images/Medium_selected.png"
      : ":/images/Medium_not_selected.png");
    assert(!pixmap.isNull());

    painter.drawPixmap(ui->widget_medium->geometry(),pixmap);
  }
  {
    //Hard
    QPixmap pixmap(m_difficulty == hard
      ? ":/images/Hard_selected.png"
      : ":/images/Hard_not_selected.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_hard->geometry(),pixmap);
  }
  {
    //Start
    QPixmap pixmap(":/images/Start.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_start->geometry(),pixmap);
  }
  {
    //Instructions
    QPixmap pixmap(":/images/Instructions.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_instructions->geometry(),pixmap);
  }
  {
    //About
    QPixmap pixmap(":/images/About.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_about->geometry(),pixmap);
  }
  {
    //Quit
    QPixmap pixmap(":/images/Quit.png");
    assert(!pixmap.isNull());
    painter.drawPixmap(ui->widget_quit->geometry(),pixmap);
  }


}

void FormMenu::onStart()
{
  boost::scoped_ptr<FormMain> d(new FormMain(0,getMazeSize()));
  this->hide();
  d->exec();
  this->show();
}

void FormMenu::onInstructions()
{
  boost::scoped_ptr<FormInstructions> d(new FormInstructions);
  this->hide();
  d->exec();
  this->show();
}

void FormMenu::onAbout()
{
  boost::scoped_ptr<FormAbout> d(new FormAbout);
  this->hide();
  d->exec();
  this->show();
}

int FormMenu::getMazeSize() const
{
  switch (m_difficulty)
  {
    case easy  : return  99;
    case medium: return 499;
    case hard  : return 999;
  }
  assert(!"Should not get here");
  throw std::logic_error("Unsupported value of mDifficulty");
}



/*
#include <vcl.h>
#pragma hdrstop

#include <ctime>
#include <stdexcept>
#include <cstdlib>
#include <boost/scoped_ptr.hpp>
#include "UnitMazeCreater.h"

#include "UnitFormMaziakMenu.h"
#include "UnitFormMaziakAbout.h"
#include "UnitFormMaziakGame.h"
#include "UnitFormMaziakInstructions.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFormMaziakMenu *FormMaziakMenu;
//---------------------------------------------------------------------------
__fastcall TFormMaziakMenu::TFormMaziakMenu(TComponent* Owner)
  : TForm(Owner),
    mDifficulty(easy)
{
  RandomizeTimer();
  ImageEasyClick(0);
}
//---------------------------------------------------------------------------
const int TFormMaziakMenu::GetSize() const
{
  switch (mDifficulty)
  {
    case easy  : return  99;
    case medium: return 499;
    case hard  : return 999;
  }
  assert(!"Should not get here");
  throw std::logic_error("Unsupported value of mDifficulty");
}
//---------------------------------------------------------------------------

void __fastcall TFormMaziakMenu::ImageStartClick(TObject *Sender)
{
  boost::scoped_ptr<TFormMaziakGame> f(new TFormMaziakGame(0,GetSize()));
  f->WindowState = wsMaximized;
  f->ShowModal();
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakMenu::ImageAboutClick(TObject *Sender)
{
  boost::scoped_ptr<TFormMaziakAbout> f(new TFormMaziakAbout(0));
  f->ShowModal();
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakMenu::ImageQuitClick(TObject *Sender)
{
  Close();
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakMenu::FormKeyDown(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
  switch (Key)
  {
    case 's': case 'S': ImageStartClick(0); break;
    case 'i': case 'I': ImageInstructionsClick(0); break;
    case 'a': case 'A': ImageAboutClick(0); break;
    case 'q': case 'Q': ImageQuitClick(0); break;
    case '+': case VK_NEXT: case VK_DOWN: case VK_ADD: case VK_RIGHT:
    {
      switch (mDifficulty)
      {
        case easy  : ImageMediumClick(0); break;
        case medium: ImageHardClick(0); break;
        case hard  : break;
      }
    }
    break;
    case '-': case VK_PRIOR: case VK_UP: case VK_SUBTRACT: case VK_LEFT:
    {
      switch (mDifficulty)
      {
        case easy  : break;
        case medium: ImageEasyClick(0); break;
        case hard  : ImageMediumClick(0);break;
      }
    }
    break;
  }
}
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppRandomizeTimer.htm
void RandomizeTimer()
{
  std::srand(std::time(0));
}
//---------------------------------------------------------------------------

void __fastcall TFormMaziakMenu::ImageInstructionsClick(TObject *Sender)
{
  boost::scoped_ptr<TFormMaziakInstructions> f(new TFormMaziakInstructions(0));
  f->ShowModal();
}
//---------------------------------------------------------------------------


void __fastcall TFormMaziakMenu::ImageEasyClick(TObject *Sender)
{
  ImageEasy->Picture   = ImageEasySelected->Picture;
  ImageMedium->Picture = ImageMediumNotSelected->Picture;
  ImageHard->Picture   = ImageHardNotSelected->Picture;
  mDifficulty = easy;
  ImagePlayer->Picture = ImagePlayerEasy->Picture;
  ImageEnemy->Picture  = ImageEnemyEasy->Picture;
}
//---------------------------------------------------------------------------

void __fastcall TFormMaziakMenu::ImageMediumClick(TObject *Sender)
{
  ImageEasy->Picture   = ImageEasyNotSelected->Picture;
  ImageMedium->Picture = ImageMediumSelected->Picture;
  ImageHard->Picture   = ImageHardNotSelected->Picture;
  mDifficulty = medium;
  ImagePlayer->Picture = ImagePlayerMedium->Picture;
  ImageEnemy->Picture  = ImageEnemyMedium->Picture;
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakMenu::ImageHardClick(TObject *Sender)
{
  ImageEasy->Picture   = ImageEasyNotSelected->Picture;
  ImageMedium->Picture = ImageMediumNotSelected->Picture;
  ImageHard->Picture   = ImageHardSelected->Picture;
  mDifficulty = hard;
  ImagePlayer->Picture = ImagePlayerHard->Picture;
  ImageEnemy->Picture  = ImageEnemyHard->Picture;
}
//---------------------------------------------------------------------------
*/

 

 

 

 

 

formmenu.h

 

#ifndef FORMMENU_H
#define FORMMENU_H

#include <QDialog>

struct QKeyPressEvent;
struct QMouseEvent;
struct QPaintEvent;

namespace Ui {
  class FormMenu;
}

class FormMenu : public QDialog
{
  Q_OBJECT

public:
  explicit FormMenu(QWidget *parent = 0);
  ~FormMenu();

protected:
  void changeEvent(QEvent *e);

private:
  Ui::FormMenu *ui;
  enum Difficulty { easy, medium, hard } m_difficulty;
  int getMazeSize() const;

  void keyPressEvent(QKeyEvent * event);
  void mousePressEvent(QMouseEvent * event);
  void paintEvent(QPaintEvent*);
  void onStart();
  void onInstructions();
  void onAbout();

private slots:

};

#endif // FORMMENU_H

 

 

 

 

 

formwhatsnew.cpp

 

#include "formwhatsnew.h"
#include "ui_formwhatsnew.h"

FormWhatsNew::FormWhatsNew(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::FormWhatsNew)
{
    ui->setupUi(this);
}

FormWhatsNew::~FormWhatsNew()
{
    delete ui;
}

void FormWhatsNew::changeEvent(QEvent *e)
{
    QDialog::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

 

 

 

 

 

formwhatsnew.h

 

#ifndef FORMWHATSNEW_H
#define FORMWHATSNEW_H

#include <QDialog>

namespace Ui {
    class FormWhatsNew;
}

class FormWhatsNew : public QDialog
{
    Q_OBJECT

public:
    explicit FormWhatsNew(QWidget *parent = 0);
    ~FormWhatsNew();

protected:
    void changeEvent(QEvent *e);

private:
    Ui::FormWhatsNew *ui;
};

#endif // FORMWHATSNEW_H

 

 

 

 

 

main.cpp

 

#include <QtGui/QApplication>
#include "formmenu.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    FormMenu w;
    w.show();
    return a.exec();
}

 

 

 

 

 

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict