Go back to Richel Bilderbeek's homepage.

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

 

 

 

 

 

(C++ game) Maziak version 1.4 source code

 

Maziak version 1.4 C++ Builder source code.

 

 

 

 

 

UnitFormMaziakAbout.cpp

 

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <boost/scoped_ptr.hpp>
#include "UnitFormMaziakAbout.h"
#include "UnitFormWhatsNew.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFormMaziakAbout *FormMaziakAbout;
//---------------------------------------------------------------------------
__fastcall TFormMaziakAbout::TFormMaziakAbout(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TFormMaziakAbout::ButtonWhatsNewClick(TObject *Sender)
{
  boost::scoped_ptr<TFormWhatsNew> f(new TFormWhatsNew(0));
  f->ShowModal();
}
//---------------------------------------------------------------------------

 

 

 

 

 

UnitFormMaziakAbout.h

 

//---------------------------------------------------------------------------
#ifndef UnitFormMaziakAboutH
#define UnitFormMaziakAboutH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <ExtCtrls.hpp>
#include <Graphics.hpp>
//---------------------------------------------------------------------------
class TFormMaziakAbout : public TForm
{
__published: // IDE-managed Components
        TImage *ImageRichelBilderbeek;
        TRichEdit *RichEditLicence;
        TPanel *PanelTop;
        TPanel *PanelTopLeft;
        TPanel *PanelUrl;
        TPanel *PanelLicence;
        TPanel *PanelAuthor;
        TPanel *PanelMaziak;
        TPanel *PanelFrom;
        TPanel *PanelVersion;
        TButton *ButtonWhatsNew;
        TPanel *PanelTo;
        TImage *ImageMaziak;
        TImage *ImageVersion;
        TImage *ImageAuthor;
        TImage *ImageFrom;
        TImage *ImageTo;
        TImage *ImageLicence;
        TImage *ImageUrl;
        void __fastcall ButtonWhatsNewClick(TObject *Sender);
private: // User declarations
public: // User declarations
        __fastcall TFormMaziakAbout(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TFormMaziakAbout *FormMaziakAbout;
//---------------------------------------------------------------------------
#endif

 

 

 

 

 

UnitFormMaziakGame.h

 

//---------------------------------------------------------------------------
#ifndef UnitFormMaziakGameH
#define UnitFormMaziakGameH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <Graphics.hpp>
//---------------------------------------------------------------------------
#include <set>
#include <list>
#include <vector>
#include "UnitLocation.h"
//---------------------------------------------------------------------------
class TFormMaziakGame : public TForm
{
__published: // IDE-managed Components
        TImage *ImageBuffer;
        TImage *ImagePlayerLookDown;
        TTimer *TimerPressKey;
        TTimer *TimerEnemy;
        TImage *ImagePlayerLookLeftSword;
        TImage *ImageSword;
        TImage *ImageExit;
        TImage *ImagePrisoner1;
        TTimer *TimerShowSolution;
        TImage *ImageEntrace;
        TImage *ImageGold;
        TImage *Image1;
        TImage *ImageFightWon1;
        TImage *ImagePlayerWon1;
        TImage *Image2;
        TImage *Image3;
        TImage *Image4;
        TImage *ImageFight1;
        TImage *ImagePlayerLookRightSword;
        TImage *ImagePlayerWalkLeft2;
        TImage *ImagePlayerWalkLeft1;
        TImage *ImagePlayerWalkLeftSword2;
        TImage *ImagePlayerWalkLeftSword1;
        TImage *ImagePlayerWalkDown1;
        TImage *ImagePlayerWalkDown2;
        TImage *ImagePlayerWalkDownSword1;
        TImage *ImagePlayerWalkDownSword2;
        TImage *ImagePlayerWalkUp2;
        TImage *ImagePlayerWalkUp1;
        TImage *ImagePlayerWalkUpSword1;
        TImage *ImagePlayerWalkUpSword2;
        TImage *ImagePlayerWalkRightSword1;
        TImage *ImagePlayerWalkRightSword2;
        TImage *ImagePlayerWalkRight1;
        TImage *ImagePlayerWalkRight2;
        TImage *ImagePlayerLookLeft;
        TImage *ImagePlayerLookRight;
        TImage *ImagePlayerLookDownSword;
        TImage *ImagePlayerLookUp;
        TImage *ImagePlayerLookUpSword;
        TImage *ImagePrisoner2;
        TImage *ImageFightWon2;
        TImage *ImageFightSword1;
        TImage *ImageFight2;
        TImage *ImageFight3;
        TImage *ImageFight4;
        TImage *ImageFightLost1;
        TImage *ImageFightLost2;
        TImage *ImageEmpty;
        TImage *ImageWall;
        TImage *ImageEnemy1;
        TImage *ImageEnemy2;
        TImage *ImagePath;
        TImage *ImagePlayerWon2;
        void __fastcall FormResize(TObject *Sender);
        void __fastcall FormKeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift);
        void __fastcall TimerPressKeyTimer(TObject *Sender);
        void __fastcall FormKeyUp(TObject *Sender, WORD &Key,
          TShiftState Shift);
        void __fastcall TimerEnemyTimer(TObject *Sender);
        void __fastcall TimerShowSolutionTimer(TObject *Sender);
private: // User declarations
  int mX;
  int mY;
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 };
private:
  const int mViewWidth;
  const int mViewHeight;
  bool mHasSword;
  int mFighting;
  bool mCheat;
  bool mShowSolution;
  PlayerDirection mDirection;
  PlayerMove mMoveNow;
  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 DrawScreen();
  const TImage * const GetMazeImage(const int x, const int y) const;
  const TImage * const GetPlayerImage(
    const PlayerDirection direction,
    const PlayerMove moveNow) const;
  void CreateMaze(const int sz);
  void DoDebugF1() const;
  void DoDebugF2() const;
public: // User declarations
  __fastcall TFormMaziakGame(TComponent* Owner, const String mazeSize);

};
//---------------------------------------------------------------------------
extern PACKAGE TFormMaziakGame *FormMaziakGame;
//---------------------------------------------------------------------------
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);
//---------------------------------------------------------------------------
const bool CanMoveTo(
  const std::vector<std::vector<TFormMaziakGame::MazeSquare> >& maze,
  const int x, const int y,
  const bool hasSword,
  const bool showSolution);
//---------------------------------------------------------------------------
template <class T>
const bool IsSquare(const std::vector<std::vector<T> >& v)
{
  if (v.empty()) return false;
  const int sz = static_cast<int>(v.size());
  const std::vector<std::vector<T> >::const_iterator j = v.end();
  std::vector<std::vector<T> >::const_iterator i = v.begin();
  for ( ; i!=j; ++i)
  {
    if (sz != static_cast<int>(i->size())) return false;
  }
  return true;
}
//---------------------------------------------------------------------------
void SetPixel(
  TImage * const image,
  const int x,
  const int y,
  const unsigned char red,
  const unsigned char green,
  const unsigned char blue);
//---------------------------------------------------------------------------
#endif

 

 

 

 

 

UnitFormMaziakGame.cpp

 

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

#include <algorithm>
#include <cassert>
#include <cmath>
#include <stdexcept>
#include <vector>
#include <boost/scoped_ptr.hpp>
#include "UnitFormMaziakGame.h"
#include "UnitMazeCreater.h"
#include "UnitFormMaziakGameOver.h"
#include "UnitFormMaziakGameWon.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFormMaziakGame *FormMaziakGame;
//---------------------------------------------------------------------------
__fastcall TFormMaziakGame::TFormMaziakGame(
  TComponent* Owner,
  const String mazeSize) //Must be String, otherwise compiler complains?!?!?
  : TForm(Owner),
    mHasSword(true),
    mFighting(0),
    mCheat(false),
    mViewWidth(9),
    mViewHeight(9),
    mDirection(pdDown),
    mMoveNow(none)
{
  CreateMaze(mazeSize.ToInt());
  assert(IsSquare(mMaze));
  assert(IsSquare(mIntMaze));
  assert(mSolution.empty() || IsSquare(mSolution));
  assert(IsSquare(mDistances));
  OnResize(0);
}
//---------------------------------------------------------------------------
void TFormMaziakGame::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;
      }

    }


    {
      /*
      //Place enemies in nondead ends
      const std::vector<std::pair<int,int> > nonDeadEnds = GetShuffledNonDeadEnds(mIntMaze);
      std::vector<std::pair<int,int> >::const_iterator nonDeadEndIterator = nonDeadEnds.begin();
      for (int i=0; i!=nEnemies; ++i)
      {
        assert(nonDeadEndIterator != nonDeadEnds.end());
        const int x = (*nonDeadEndIterator).first;
        const int y = (*nonDeadEndIterator).second;
        assert(x!=mX || y!=mY);
        assert(mMaze[y][x] == msEmpty);
        mMaze[y][x] = msEnemy1;
        ++nonDeadEndIterator;
      }
      */
    }

  }
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakGame::FormResize(TObject *Sender)
{
  ImageBuffer->Picture->Bitmap->Width = ClientWidth;
  ImageBuffer->Picture->Bitmap->Height = ClientHeight;

  DrawScreen();
}
//---------------------------------------------------------------------------
void TFormMaziakGame::DrawScreen()
{
  const int sz = static_cast<int>(mMaze.size());
  const int block_width = 1 + (ClientWidth / mViewWidth );
  const int block_height = 1 + (ClientHeight / mViewHeight);

  if (mFighting > 0)
  {
    ++mFighting;
    if (mFighting == 13)
    {
      if (!mHasSword)
      {
        //Game over
        TimerPressKey->Enabled = false;
        TimerEnemy->Enabled = false;
        TimerShowSolution->Enabled = false;
        boost::scoped_ptr<TFormMaziakGameOver> f(new TFormMaziakGameOver(0));
        f->ShowModal();
        Close();
      }
      mFighting = 0;
      mHasSword = false;
    }
  }

  //Player-environment interactions
  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;
      TimerShowSolution->Enabled = true;
      break;
    case msSword:
      mMaze[mY][mX] = msEmpty;
      mHasSword = true;
      break;
    case msExit:
      TimerPressKey->Enabled = false;
      TimerEnemy->Enabled = false;
      TimerShowSolution->Enabled = false;
      boost::scoped_ptr<TFormMaziakGameWon> f(new TFormMaziakGameWon(0));
      f->ShowModal();
      Close();
  }

  //Draw maze on buffer
  for (int y=0; y!=mViewHeight; ++y)
  {
    for (int x=0; x!=mViewWidth; ++x)
    {
      const int xVector = mX - (mViewWidth / 2) + x;
      const int yVector = mY - (mViewHeight / 2) + y;

      const TRect r(
        (x * block_width )+0 , //Left
        (y * block_height)+0 , //Top
        (x * block_width )+block_width , //Right
        (y * block_height)+block_height); //Bottom

      //Clean square with black or golden path
      if ( xVector >= 0
        && yVector >= 0
        && xVector < sz
        && yVector < sz
        && ( mMaze[yVector][xVector] == msEmpty
           || mMaze[yVector][xVector] == msEnemy1
           || mMaze[yVector][xVector] == msEnemy2)
        && mShowSolution
        && mSolution[yVector][xVector] == 1)
      {
        //Golden path
        ImageBuffer->Canvas->StretchDraw(r,ImagePath->Picture->Graphic);
      }
      else
      {
        ImageBuffer->Canvas->StretchDraw(r,ImageEmpty->Picture->Graphic);
      }

      //Draw real image
      const TImage * image = GetMazeImage(xVector,yVector);
      assert(image);
      ImageBuffer->Canvas->StretchDraw(r,image->Picture->Graphic);
    }
  }

  //Draw player on buffer
  {
    const TRect r(
      ((mViewWidth / 2) * block_width )+0 , //Left
      ((mViewHeight / 2) * block_height)+0 , //Top
      ((mViewWidth / 2) * block_width )+block_width , //Right
      ((mViewHeight / 2) * block_height)+block_height); //Bottom
    const TImage * const imagePlayer = GetPlayerImage(mDirection,mMoveNow);
    assert(imagePlayer);
    ImageBuffer->Canvas->StretchDraw(r,imagePlayer->Picture->Graphic);
  }

  //Draw buffer to screen
  this->Canvas->Draw(0,0,ImageBuffer->Picture->Graphic);

}
//---------------------------------------------------------------------------
//Get the TImage from mMaze at (x,y)
const TImage * const TFormMaziakGame::GetMazeImage(
  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 ImageWall;
  }
  if ( mMaze[y][x] == msEmpty
    && mShowSolution
    && mSolution[y][x] == 1)
  {
    return ImagePath;
  }
  //What else here?
  switch(mMaze[y][x])
  {
    case msEmpty : return ImageEmpty;
    case msWall : return ImageWall;
    case msEnemy1 : return ImageEnemy1;
    case msEnemy2 : return ImageEnemy2;
    case msPrisoner1 : return ImagePrisoner1;
    case msPrisoner2 : return ImagePrisoner2;
    case msSword : return ImageSword;
    case msExit : return ImageExit;
    default:
      assert(!"Should not get here");
      throw std::logic_error("Unexpected MazeSquare at mMaze");
  }
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakGame::FormKeyDown(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
  if (mFighting > 0) DrawScreen();

  mKeys.insert(Key);

  switch (Key)
  {
    case VK_LEFT : mKeys.erase(VK_RIGHT); break;
    case VK_RIGHT: mKeys.erase(VK_LEFT ); break;
    case VK_UP : mKeys.erase(VK_DOWN ); break;
    case VK_DOWN : mKeys.erase(VK_UP ); break;
    case VK_F1 : DoDebugF1(); break;
    case VK_F2 : DoDebugF2(); break;
  }

  if (mKeys.count(VK_F6)!=0 && mKeys.count(VK_F9)!=0) mCheat = true;
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakGame::FormKeyUp(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
  mKeys.erase(Key);
  if (mKeys.count(VK_F6)==0 || mKeys.count(VK_F9)==0) mCheat = false;
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakGame::TimerPressKeyTimer(TObject *Sender)
{
  if (mFighting > 0) return;
  if (mKeys.empty()) { mMoveNow = none; }

  const std::set<WORD>::const_iterator j = mKeys.end();
  for(std::set<WORD>::const_iterator i = mKeys.begin(); i!=j; ++i)
  {
    //Check the keys pressed
    switch (*i)
    {
      case VK_LEFT :
        mDirection = pdLeft;
        if (!CanMoveTo(mMaze,mX-1,mY,mHasSword,mShowSolution))
        {
          mMoveNow = none;
          continue;
        }
        mMoveNow = (mMoveNow == left1 ? left2 : left1);
        --mX;
        break;
      case VK_RIGHT:
        mDirection = pdRight;
        if (!CanMoveTo(mMaze,mX+1,mY,mHasSword,mShowSolution))
        {
          mMoveNow = none;
          continue;
        }
        mMoveNow = (mMoveNow == right1 ? right2 : right1);
        ++mX;
        break;
      case VK_UP :
        mDirection = pdUp;
        if (!CanMoveTo(mMaze,mX,mY-1,mHasSword,mShowSolution))
        {
          mMoveNow = none;
          continue;
        }
        mMoveNow = (mMoveNow == up1 ? up2 : up1);
        --mY;
        break;
      case VK_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
    DrawScreen();
  }
}
//---------------------------------------------------------------------------
const bool CanMoveTo(
  const std::vector<std::vector<TFormMaziakGame::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 TFormMaziakGame::MazeSquare s = maze[y][x];
  //Bump into wall
  if (s == TFormMaziakGame::msWall) return false;
  //Bump into sword
  if (s == TFormMaziakGame::msSword && hasSword) return false;
  //Bump into prisoner
  if (showSolution
    && (s == TFormMaziakGame::msPrisoner1
     || s == TFormMaziakGame::msPrisoner2) ) return false;
  //Bump into empty/enemy/exit, so player can move there
  return true;
}
//---------------------------------------------------------------------------
void TFormMaziakGame::DoDebugF1() const
{
  const int sizeVector = mMaze.size();

  for (int y=0; y!=mViewHeight; ++y)
  {
    String debug;
    debug+=y;
    debug+=':';
    for (int x=0; x!=mViewWidth; ++x)
    {
      const int xVector = mX - (mViewWidth / 2) + x;
      const int yVector = mY - (mViewHeight / 2) + y;

      if ( xVector >= 0
        && xVector < sizeVector
        && yVector >= 0
        && yVector < sizeVector)
      {
        debug+=static_cast<int>(mMaze[yVector][xVector]);
      }
      else
      {
        debug+='x';
      }
    }
    OutputDebugString(debug.c_str());
  }

}
//---------------------------------------------------------------------------
void TFormMaziakGame::DoDebugF2() const
{
  //Obtain a bitmap of the entire maze
  const int sz = mMaze.size();
  Extctrls::TImage * const image = new Extctrls::TImage(0);
  image->Picture->Graphic = ImageEmpty->Picture->Graphic;
  image->Picture->Bitmap->Width = sz;
  image->Picture->Bitmap->Height = sz;

  for (int y=0; y!=sz; ++y)
  {
    for (int x=0; x!=sz; ++x)
    {
      const MazeSquare s = mMaze[y][x];
      switch(s)
      {
        case msEmpty : SetPixel(image,x,y,255,255,255); break;
        case msWall : SetPixel(image,x,y, 0, 0, 0); break;
        case msEnemy1 : SetPixel(image,x,y, 0, 0,255); break;
        case msEnemy2 : SetPixel(image,x,y,127,127,255); break;
        case msPrisoner1 : SetPixel(image,x,y, 0,255, 0); break;
        case msPrisoner2 : SetPixel(image,x,y,127,255,127); break;
        case msSword : SetPixel(image,x,y,255, 0, 0); break;
        case msExit : SetPixel(image,x,y,255,127,127); break;
      }
    }
  }
  //Player
  SetPixel(image,mX,mY,255,255, 0);

  image->Picture->SaveToFile("debug.bmp");

}
//---------------------------------------------------------------------------
const TImage * const TFormMaziakGame::GetPlayerImage(
  const PlayerDirection direction,
  const PlayerMove moveNow) const
{
  switch (mFighting)
  {
    case 0: break;
    case 1: return (mHasSword ? ImageFightSword1 : ImageFight1);
    case 2: return ImageFight2;
    case 3: return ImageFight3;
    case 4: return ImageFight4;
    case 5: return (mHasSword ? ImageFightSword1 : ImageFight1);
    case 6: return ImageFight2;
    case 7: return ImageFight3;
    case 8: return ImageFight4;
    case 9: return (mHasSword ? ImageFightWon1 : ImageFightLost1);
    case 10: return (mHasSword ? ImageFightWon2 : ImageFightLost2);
    case 11: return (mHasSword ? ImageFightWon1 : ImageFightLost1);
    case 12: return (mHasSword ? ImageFightWon2 : ImageFightLost2);
  }

  switch (direction)
  {
    case pdUp:
    {
      switch (moveNow)
      {
        case none: return (mHasSword ? ImagePlayerLookUpSword : ImagePlayerLookUp);
        case up1: return (mHasSword ? ImagePlayerWalkUpSword1 : ImagePlayerWalkUp1);
        case up2: return (mHasSword ? ImagePlayerWalkUpSword2 : ImagePlayerWalkUp2);
        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 ? ImagePlayerLookRightSword : ImagePlayerLookRight);
        case right1: return (mHasSword ? ImagePlayerWalkRightSword1 : ImagePlayerWalkRight1);
        case right2: return (mHasSword ? ImagePlayerWalkRightSword2 : ImagePlayerWalkRight2);
        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 ? ImagePlayerLookDownSword : ImagePlayerLookDown);
        case down1: return (mHasSword ? ImagePlayerWalkDownSword1 : ImagePlayerWalkDown1);
        case down2: return (mHasSword ? ImagePlayerWalkDownSword2 : ImagePlayerWalkDown2);
        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 ? ImagePlayerLookLeftSword : ImagePlayerLookLeft);
        case left1: return (mHasSword ? ImagePlayerWalkLeftSword1 : ImagePlayerWalkLeft1);
        case left2: return (mHasSword ? ImagePlayerWalkLeftSword2 : ImagePlayerWalkLeft2);
        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 __fastcall TFormMaziakGame::TimerEnemyTimer(TObject *Sender)
{
  //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;
      }
    }
  }
  DrawScreen();
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakGame::TimerShowSolutionTimer(TObject *Sender)
{
  mShowSolution = false;
  TimerShowSolution->Enabled = false;
}
//---------------------------------------------------------------------------
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;
}
//---------------------------------------------------------------------------
const std::vector<std::pair<int,int> > GetShuffledNonDeadEnds(
  const std::vector<std::vector<int> >& intMaze)
{
  std::vector<std::pair<int,int> > nonDeadEnds = GetNonDeadEnds(intMaze);
  std::random_shuffle(nonDeadEnds.begin(), nonDeadEnds.end());
  return nonDeadEnds;
}
//---------------------------------------------------------------------------
//Set a pixel's RGB values
//From http://www.richelbilderbeek.nl
void SetPixel(
  TImage * const image,
  const int x,
  const int y,
  const unsigned char red,
  const unsigned char green,
  const unsigned char blue)
{
  assert(image!=0 && "Image is NULL");
  assert(image->Picture->Bitmap!=0 && "Bitmap is NULL");
  assert(image->Picture->Bitmap->PixelFormat == pf24bit && "Bitmap must be 24 bit");
  assert( x >= 0 && "x coordinat is below zero");
  assert( y >= 0 && "y coordinat is below zero");
  assert( x < image->Picture->Bitmap->Width && "x coordinat is beyond image width");
  assert( y < image->Picture->Bitmap->Height && "y coordinat is beyond image height");

  unsigned char * const line
    = static_cast<unsigned char *>(image->Picture->Bitmap->ScanLine[y]);

  line[x*3+2] = red;
  line[x*3+1] = green;
  line[x*3+0] = blue;
}
//---------------------------------------------------------------------------

 

 

 

 

 

UnitFormMaziakGameOver.h

 


//---------------------------------------------------------------------------
#ifndef UnitFormMaziakGameOverH
#define UnitFormMaziakGameOverH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <Graphics.hpp>
//---------------------------------------------------------------------------
class TFormMaziakGameOver : public TForm
{
__published: // IDE-managed Components
        TImage *ImageGrave;
        TTimer *Timer1;
        TImage *ImageTop;
        TImage *ImageBottom;
        void __fastcall OnAnyClick(TObject *Sender);
        void __fastcall Timer1Timer(TObject *Sender);
        void __fastcall FormKeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift);
private: // User declarations
  bool mCanClose;
public: // User declarations
        __fastcall TFormMaziakGameOver(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TFormMaziakGameOver *FormMaziakGameOver;
//---------------------------------------------------------------------------
void DrawGrave(const TImage * image);

#endif

 

 

 

 

 

UnitFormMaziakGameOver.cpp

 


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

#include "UnitFormMaziakGameOver.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFormMaziakGameOver *FormMaziakGameOver;
//---------------------------------------------------------------------------
__fastcall TFormMaziakGameOver::TFormMaziakGameOver(TComponent* Owner)
        : TForm(Owner), mCanClose(false)
{
}
//---------------------------------------------------------------------------

void __fastcall TFormMaziakGameOver::OnAnyClick(TObject *Sender)
{
  Close();
}
//---------------------------------------------------------------------------

void __fastcall TFormMaziakGameOver::Timer1Timer(TObject *Sender)
{
  mCanClose = true;
}
//---------------------------------------------------------------------------

void __fastcall TFormMaziakGameOver::FormKeyDown(TObject *Sender,
      WORD &Key, TShiftState Shift)
{
  if (mCanClose == true) Close();
}
//---------------------------------------------------------------------------

 

 

 

 

 

UnitFormMaziakGameWon.h

 


//---------------------------------------------------------------------------
#ifndef UnitFormMaziakGameWonH
#define UnitFormMaziakGameWonH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <Graphics.hpp>
//---------------------------------------------------------------------------
class TFormMaziakGameWon : public TForm
{
__published: // IDE-managed Components
        TImage *ImagePlayerWon1;
        TTimer *TimerCanClose;
        TImage *ImageTop;
        TImage *ImageBottom;
        TImage *ImagePlayerWon2;
        TTimer *TimerAnimation;
        TImage *ImageBuffer;
        TImage *ImageEmpty;
        void __fastcall OnAnyClick(TObject *Sender);
        void __fastcall TimerCanCloseTimer(TObject *Sender);
        void __fastcall FormKeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift);
        void __fastcall TimerAnimationTimer(TObject *Sender);
private: // User declarations
  bool mCanClose;
public: // User declarations
        __fastcall TFormMaziakGameWon(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TFormMaziakGameWon *FormMaziakGameWon;
//---------------------------------------------------------------------------
#endif

 

 

 

 

 

UnitFormMaziakGameWon.cpp

 

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

#include "UnitFormMaziakGameWon.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFormMaziakGameWon *FormMaziakGameWon;
//---------------------------------------------------------------------------
__fastcall TFormMaziakGameWon::TFormMaziakGameWon(TComponent* Owner)
        : TForm(Owner), mCanClose(false)
{
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakGameWon::OnAnyClick(TObject *Sender)
{
  Close();
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakGameWon::TimerCanCloseTimer(TObject *Sender)
{
  mCanClose = true;
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakGameWon::FormKeyDown(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
  if (mCanClose == true) Close();
}
//---------------------------------------------------------------------------
void __fastcall TFormMaziakGameWon::TimerAnimationTimer(TObject *Sender)
{
  ++TimerAnimation->Tag;
  //Clear the buffer
  ImageBuffer->Canvas->Draw(0,0,ImageEmpty->Picture->Graphic);
  //Draw right image on buffer
  const TImage * const image = (TimerAnimation->Tag % 2 ? ImagePlayerWon1 : ImagePlayerWon2);
  ImageBuffer->Canvas->Draw(0,0,image->Picture->Graphic);
  //Draw buffer on canvar
  TRect r(ClientRect);
  r.top+=ImageTop->Height;
  r.bottom-=ImageBottom->Height;
  this->Canvas->StretchDraw(r,ImageBuffer->Picture->Graphic);

}
//---------------------------------------------------------------------------

 

 

 

 

 

UnitFormMaziakInstructions.h

 

//---------------------------------------------------------------------------
#ifndef UnitFormMaziakInstructionsH
#define UnitFormMaziakInstructionsH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <ExtCtrls.hpp>
#include <Graphics.hpp>
//---------------------------------------------------------------------------
class TFormMaziakInstructions : public TForm
{
__published: // IDE-managed Components
        TImage *Image1;
        TImage *Image3;
        TImage *Image4;
        TImage *Image5;
        TImage *Image6;
        TLabel *Label1;
        TLabel *Label2;
        TLabel *Label3;
        TLabel *Label4;
        TLabel *Label5;
        TImage *Image2;
        TImage *Image7;
        TImage *Image8;
        TImage *Image9;
        TImage *Image10;
        TImage *Image11;
        TImage *Image12;
        TImage *Image13;
        TImage *Image15;
        TImage *Image16;
        TImage *Image17;
        TImage *Image18;
        TImage *Image19;
        TImage *Image20;
        TImage *Image21;
        void __fastcall ButtonWhatsNewClick(TObject *Sender);
private: // User declarations
public: // User declarations
        __fastcall TFormMaziakInstructions(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TFormMaziakInstructions *FormMaziakInstructions;
//---------------------------------------------------------------------------
#endif

 

 

 

 

 

UnitFormMaziakInstructions.cpp

 

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

#include <boost/scoped_ptr.hpp>
#include "UnitFormMaziakInstructions.h"
#include "UnitFormWhatsNew.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFormMaziakInstructions *FormMaziakInstructions;
//---------------------------------------------------------------------------
__fastcall TFormMaziakInstructions::TFormMaziakInstructions(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

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

 

 

 

 

 

UnitFormMaziakMenu.h

 

//---------------------------------------------------------------------------
#ifndef UnitFormMaziakMenuH
#define UnitFormMaziakMenuH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <Graphics.hpp>
//---------------------------------------------------------------------------
class TFormMaziakMenu : public TForm
{
__published: // IDE-managed Components
        TImage *ImagePlayer;
        TImage *ImageQuit;
        TImage *ImageAbout;
        TImage *ImageStart;
        TImage *ImageInstructions;
        TImage *ImageEasy;
        TImage *ImageMedium;
        TImage *ImageHard;
        TImage *ImageEasySelected;
        TImage *ImageMediumSelected;
        TImage *ImageHardSelected;
        TImage *ImageEasyNotSelected;
        TImage *ImageMediumNotSelected;
        TImage *ImageHardNotSelected;
        TImage *ImagePlayerHard;
        TImage *ImagePlayerEasy;
        TImage *ImagePlayerMedium;
        TImage *ImageEnemy;
        TImage *ImageEnemyHard;
        TImage *ImageEnemyMedium;
        TImage *ImageEnemyEasy;
        void __fastcall ImageQuitClick(TObject *Sender);
        void __fastcall ImageAboutClick(TObject *Sender);
        void __fastcall ImageStartClick(TObject *Sender);
        void __fastcall FormKeyDown(TObject *Sender, WORD &Key,
          TShiftState Shift);
        void __fastcall ImageInstructionsClick(TObject *Sender);
        void __fastcall ImageEasyClick(TObject *Sender);
        void __fastcall ImageMediumClick(TObject *Sender);
        void __fastcall ImageHardClick(TObject *Sender);
private: // User declarations
  const int GetSize() const;
  enum Difficulty { easy, medium, hard } mDifficulty;
public: // User declarations
        __fastcall TFormMaziakMenu(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TFormMaziakMenu *FormMaziakMenu;
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppRandomizeTimer.htm
void RandomizeTimer();
//---------------------------------------------------------------------------

#endif

 

 

 

 

 

UnitFormMaziakMenu.cpp

 

//---------------------------------------------------------------------------
#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;
}
//---------------------------------------------------------------------------

 

 

 

 

 

UnitFormWhatsNew.h

 

//---------------------------------------------------------------------------
#ifndef UnitFormWhatsNewH
#define UnitFormWhatsNewH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
//---------------------------------------------------------------------------
class TFormWhatsNew : public TForm
{
__published: // IDE-managed Components
        TRichEdit *RichEdit;
private: // User declarations
public: // User declarations
        __fastcall TFormWhatsNew(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TFormWhatsNew *FormWhatsNew;
//---------------------------------------------------------------------------
#endif

 

 

 

 

 

UnitFormWhatsNew.cpp

 

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

#include "UnitFormWhatsNew.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFormWhatsNew *FormWhatsNew;
//---------------------------------------------------------------------------
__fastcall TFormWhatsNew::TFormWhatsNew(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

 

 

 

 

 

UnitLocation.h

 

//---------------------------------------------------------------------------
#ifndef UnitLocationH
#define UnitLocationH
//---------------------------------------------------------------------------
struct Location
{
  Location() : x(0), y(0) {}
  Location(const int anyX, const int anyY) : x(anyX), y(anyY) {}
  int x;
  int y;
};
bool operator==(const Location& lhs, const Location& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; }

#endif

 

 

 

 

 

UnitLocation.cpp

 

//---------------------------------------------------------------------------
#pragma hdrstop

#include "UnitLocation.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

 

 

 

 

 

UnitMazeCreater.h

 

//---------------------------------------------------------------------------
#ifndef UnitMazeCreaterH
#define UnitMazeCreaterH
//---------------------------------------------------------------------------
#include <vector>

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

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

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

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

//From http://www.richelbilderbeek.nl/CppCreateSloppyMaze.htm
const std::vector<std::vector<int> > CreateSloppyMazeOld(const int size, const double fractionPerfect);

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

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

//From http://www.richelbilderbeek.nl/CppCountDeadEnds.htm
const int CountDeadEnds(const std::vector<std::vector<int> >& maze);

//From http://www.richelbilderbeek.nl/CppSolveMaze.htm
const std::vector<std::vector<int> > SolveMaze(
  const std::vector<std::vector<int> >& maze,
  const int x1,
  const int y1,
  const int x2,
  const int y2);

//From http://www.richelbilderbeek.nl/CppCountNonDeadEnds.htm
const int CountNonDeadEnds(const std::vector<std::vector<int> >& maze);

#endif

 

 

 

 

 

UnitMazeCreater.cpp

 

/---------------------------------------------------------------------------
#pragma hdrstop

#include <algorithm>
#include <cassert>

#include "UnitMazeCreater.h"
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/GetMazeDistances
const 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;
}
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/GetMazeDistances
std::vector<std::vector<int> > GetMazeDistancesSlow(
  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
    bool newDistanceFound = true;

    while(newDistanceFound == true)
    {
      ++distance;
      newDistanceFound = false;
      for (int y=0; y!=size; ++y)
      {
        for (int x=0; x!=size; ++x)
        {
          //Check if this spot can be assigned a distance value
          if (maze[y][x] != 0) continue; //Continue if here is a wall
          if (distances[y][x] != maxDistance) continue; //Continue if already in solution
          if ( x!=0 && distances[y][x-1] == distance - 1 )
          { distances[y][x] = distance; newDistanceFound = true; continue; }
          if ( x!=size-1 && distances[y][x+1] == distance - 1 )
          { distances[y][x] = distance; newDistanceFound = true; continue; }
          if ( y!=0 && distances[y-1][x] == distance - 1 )
          { distances[y][x] = distance; newDistanceFound = true; continue; }
          if ( y!=size-1 && distances[y+1][x] == distance - 1 )
          { distances[y][x] = distance; newDistanceFound = true; continue; }
        }
      }

    }
  }
  return distances;
}
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/GetDistancesPath.htm
const 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;
}
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppSolveMaze.htm
const std::vector<std::vector<int> > SolveMaze(
  const std::vector<std::vector<int> >& maze,
  const int x1,
  const int y1,
  const int x2,
  const int y2)
{
  //Assume maze is square
  assert(maze[0].size() == maze.size());
  assert(maze[y1][x1] == 0); //Assume starting point is no wall
  assert(maze[y2][x2] == 0); //Assume end point is no wall

  const std::vector<std::vector<int> > distances(GetMazeDistances(maze,x2,y2));
  return GetDistancesPath(distances,x1,y1);
}
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppCountDeadEnds.htm
const int CountDeadEnds(const std::vector<std::vector<int> >& maze)
{
  const int size = maze.size();

  int nDeadEnds = 0;

  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) ++nDeadEnds;

    }
  }
  return nDeadEnds;
}
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppGetDeadEnds.htm
const 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/CppGetNonDeadEnds.htm
const std::vector<std::pair<int,int> > GetNonDeadEnds(const std::vector<std::vector<int> >& maze)
{
  const int size = maze.size();

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

  for (int y=1; y!=size-1; ++y)
  {
    assert( y < static_cast<int>(maze.size()) && "y must be in range");
    assert( maze.size() == maze[y].size() && "Maze must be square");
    for (int x=1; x!=size-1; ++x)
    {
      assert( x < static_cast<int>(maze[y].size()) && "x must be in range");
      if (maze[y][x] != 0) continue; //Continue if here is a wall
      assert(maze[y][x] == 0);
      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) nonDeadEnds.push_back(std::make_pair(x,y));

    }
  }
  return nonDeadEnds;
}
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/CppCreateSloppyMaze.htm
const std::vector<std::vector<int> > CreateSloppyMazeOld(const int size, const double fractionPerfect)
{
  //Size must be odd
  assert( size % 2 == 1);
  assert( fractionPerfect >= 0.0 && fractionPerfect <= 1.0);

  std::vector<std::vector<int> > maze(size, std::vector<int>(size,0));

  //Draw outer walls
  for (int i=0; i!=size; ++i)
  {
    maze[0] [i ] = 1;
    maze[size-1][i ] = 1;
    maze[i] [0 ] = 1;
    maze[i] [size-1] = 1;
  }

  //Draw pillars
  for (int y=2; y!=size-1; y+=2)
  {
    for (int x=2; x!=size-1; x+=2)
    {
      maze[y][x] = 1;
    }
  }

  //Check around pillars
  const int nWallsToAdd
    = static_cast<int>(fractionPerfect
      * static_cast<double>(((size / 2) - 1) * ((size / 2) - 1)));
  assert(nWallsToAdd <=(((size / 2) - 1) * ((size / 2) - 1)));

  for (int i=0; i < nWallsToAdd; ) //'<' as there might be 2 walls added
  {

    for (int y=2; y!=size-1; y+=2)
    {
      for (int x=2; x!=size-1; x+=2)
      {
        const int nWalls
          = (maze[y-1][x] == 0 ? 0 : 1)
          + (maze[y+1][x] == 0 ? 0 : 1)
          + (maze[y][x+1] == 0 ? 0 : 1)
          + (maze[y][x-1] == 0 ? 0 : 1);
        if ( nWalls == 0)
        {
          switch(std::rand() % 4)
          {
            case 0: maze[y-1][x] = 1; break;
            case 1: maze[y+1][x] = 1; break;
            case 2: maze[y][x+1] = 1; break;
            case 3: maze[y][x-1] = 1; break;
          }
          ++i;
        }
        else if (nWalls == 1)
        {
          switch(std::rand() % 6)
          {
            case 0: std::swap(maze[y-1][x], maze[y+1][x]); break;
            case 1: std::swap(maze[y-1][x], maze[y][x+1]); break;
            case 2: std::swap(maze[y-1][x], maze[y][x-1]); break;
            case 3: std::swap(maze[y+1][x], maze[y][x+1]); break;
            case 4: std::swap(maze[y+1][x], maze[y][x-1]); break;
            case 5: std::swap(maze[y][x+1], maze[y][x-1]); break;
          }
        }
      }
    }
  }
  return maze;
}
//---------------------------------------------------------------------------
//Creates a maze
// 0 : path
// 1 : wall
//From http://www.richelbilderbeek.nl/CppCreateMaze.htm
const std::vector<std::vector<int> > CreateMaze(const int sz)
{
  //Size must be odd
  assert( sz % 2 == 1);

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

  //Prepare maze, remove paths
  // XXXXXXX
  // X X X X
  // XXXXXXX
  // X XOX X
  // XXXXXXX
  // X X X X
  // XXXXXXX

  //Draw open spaces
  for (int y=1; y!=sz-2; y+=2)
  {
    for (int x=1; x!=sz-2; 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/CppCreateMaze.htm
const std::vector<std::vector<int> > CreateMazeOld(const int size)
{
  //Size must be odd
  assert( size % 2 == 1);

  std::vector<std::vector<int> > maze(size, std::vector<int>(size,0));

  //Draw outer walls
  for (int i=0; i!=size; ++i)
  {
    maze[0] [i ] = 1;
    maze[size-1][i ] = 1;
    maze[i] [0 ] = 1;
    maze[i] [size-1] = 1;
  }

  //Draw pillars
  for (int y=2; y!=size-1; y+=2)
  {
    for (int x=2; x!=size-1; x+=2)
    {
      maze[y][x] = 1;
    }
  }

  //Check around pillars
  const int nWallsToAdd = ((size / 2) - 1) * ((size / 2) - 1);
  for (int i=0; i != nWallsToAdd; )
  {

    for (int y=2; y!=size-1; y+=2)
    {
      for (int x=2; x!=size-1; x+=2)
      {
        const int nWalls
          = (maze[y-1][x] == 0 ? 0 : 1)
          + (maze[y+1][x] == 0 ? 0 : 1)
          + (maze[y][x+1] == 0 ? 0 : 1)
          + (maze[y][x-1] == 0 ? 0 : 1);
        if ( nWalls == 0)
        {
          switch(std::rand() % 4)
          {
            case 0: maze[y-1][x] = 1; break;
            case 1: maze[y+1][x] = 1; break;
            case 2: maze[y][x+1] = 1; break;
            case 3: maze[y][x-1] = 1; break;
          }
          ++i;
        }
        else if (nWalls == 1)
        {
          switch(std::rand() % 6)
          {
            case 0: std::swap(maze[y-1][x], maze[y+1][x]); break;
            case 1: std::swap(maze[y-1][x], maze[y][x+1]); break;
            case 2: std::swap(maze[y-1][x], maze[y][x-1]); break;
            case 3: std::swap(maze[y+1][x], maze[y][x+1]); break;
            case 4: std::swap(maze[y+1][x], maze[y][x-1]); break;
            case 5: std::swap(maze[y][x+1], maze[y][x-1]); break;
          }
        }
      }
    }
  }
  return maze;
}
//---------------------------------------------------------------------------

#pragma package(smart_init)

 

 

 

 

 

ProjectMaziak.cpp

 

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
USEFORM("UnitFormMaziakInstructions.cpp", FormMaziakInstructions);
USEFORM("UnitFormMaziakMenu.cpp", FormMaziakMenu);
USEFORM("UnitFormMaziakGame.cpp", FormMaziakGame);
USEFORM("UnitFormMaziakGameOver.cpp", FormMaziakGameOver);
USEFORM("UnitFormMaziakGameWon.cpp", FormMaziakGameWon);
USEFORM("UnitFormWhatsNew.cpp", FormWhatsNew);
USEFORM("UnitFormMaziakAbout.cpp", FormMaziakAbout);
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
        try
        {
                 Application->Initialize();
                 Application->Title = "Maziak";
                 Application->CreateForm(__classid(TFormMaziakMenu), &FormMaziakMenu);
                 Application->Run();
        }
        catch (Exception &exception)
        {
                 Application->ShowException(&exception);
        }
        catch (...)
        {
                 try
                 {
                         throw Exception("");
                 }
                 catch (Exception &exception)
                 {
                         Application->ShowException(&exception);
                 }
        }
        return 0;
}
//---------------------------------------------------------------------------

 

 

 

 

 

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

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict