Go back to Richel Bilderbeek's homepage.

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

 

 

 

 

 

(C++) QtPylos

 

QtQt CreatorLubuntu

 

CppQtPylos is a Qt class for displaying a Pylos game.

Technical facts

 

 

 

 

 

 

./CppQtPylos/CppQtPylos.pri

 

INCLUDEPATH += \
    ../../Classes/CppQtPylos

SOURCES += \
    ../../Classes/CppQtPylos/qtpyloswidget.cpp \
    ../../Classes/CppQtPylos/qtpylossprites.cpp \
    ../../Classes/CppQtPylos/qtpylosgamewidget.cpp \
    ../../Classes/CppQtPylos/qtpylosboardwidget.cpp

HEADERS  += \
    ../../Classes/CppQtPylos/qtpyloswidget.h \
    ../../Classes/CppQtPylos/qtpylossprites.h \
    ../../Classes/CppQtPylos/qtpylosgamewidget.h \
    ../../Classes/CppQtPylos/qtpylosboardwidget.h

OTHER_FILES += \
    ../../Classes/CppQtPylos/Licence.txt

 

 

 

 

 

./CppQtPylos/qtpylosboardwidget.h

 

//---------------------------------------------------------------------------
/*
PylosWidget, widget to display Pylos class
Copyright (C) 2010-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/ToolTestPylos.htm
//---------------------------------------------------------------------------
#ifndef QTPYLOSBOARDWIDGET_H
#define QTPYLOSBOARDWIDGET_H

#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/tuple/tuple.hpp>
#include <boost/shared_ptr.hpp>

#include <QWidget>

#include "qtpyloswidget.h"
#include "pylosboard.h"
#pragma GCC diagnostic pop

struct QPaintEvent;

namespace ribi {
namespace pylos {

///PylosWidget manages a pylos::Board and facilitates its user interface
class QtPylosBoardWidget : public QtPylosWidget
{
  Q_OBJECT
public:
  QtPylosBoardWidget();
  QtPylosBoardWidget(const QtPylosBoardWidget&) = delete;
  QtPylosBoardWidget& operator=(const QtPylosBoardWidget&) = delete;
  ~QtPylosBoardWidget() noexcept {}

  ///CanRemove specifies if current player can remove one or
  ///two marble(s) at the requested position(s).
  bool CanRemove(const std::vector<pylos::Coordinat>& v) const;

  ///CanSet tests if the current player can be set at the Coordinat
  bool CanSet(const pylos::Coordinat& c) const;

  ///CanSetPlayer determines is the active Player can be changed.
  ///CanSetPlayer returns false if there are marbles to be removed
  bool CanSetPlayer(const pylos::Player player) const;

  ///CanTransfer specifies if current player can transfer
  ///the marble at the specified coordinat for movement
  bool CanTransfer(const pylos::Coordinat& c) const;

  ///CanTransfer specifies if current player can transfer his marble
  ///to a new, higher position
  bool CanTransfer(
    const pylos::Coordinat& from,
    const pylos::Coordinat& to) const;

  ///GetPylos returns a read-only pylos
  const pylos::Board * GetBoard() { return m_board.get(); }

  ///GetCurrentTurn returns whose turn it is now
  pylos::Player GetCurrentTurn() const;

  ///GetLayerSize returns how many marbles this is wide/height.
  ///For exaple; layer 0 has 4x4 marbles, so GetLayerSize
  ///will return 4.
  int GetLayerSize(const int layer) const;

  ///Obtain the MustRemoveState of the widget
  pylos::MustRemoveState GetMustRemove() const { return m_must_remove; }

  ///Obtain the PositionState at a certain coordinat
  pylos::PositionState Get(const pylos::Coordinat& c) const;

  ///GetSelector returns the selector's current coodinat
  //const pylos::Coordinat& GetSelector() const { return m_select; }

  ///Obtain this class its version
  static std::string GetVersion() noexcept;

  ///Obtain this class its version history
  static std::vector<std::string> GetVersionHistory() noexcept;

  ///Return the possible winner
  pylos::Winner GetWinner() const;

  ///Remove lets the current player remove one or two marbles
  void Remove(const std::vector<pylos::Coordinat>& v);

  ///Set makes current player place his marble
  ///at the specified position. After Set,
  ///GetMustRemove must be called to determine if
  ///the current player must remove some marbles
  void Set(const pylos::Coordinat& c);

  ///SetPlayer determines which player is allowed to make a move
  void SetPlayer(const pylos::Player player);

  ///StartAdvanced cleans the board to start a game
  ///with advanced rules
  void StartAdvanced();

  ///StartBasic cleans the board to start a game
  ///with basic rules
  void StartBasic();

  ///Transfer lets current player tranfer his marble to a new, higher position
  void Transfer(
    const pylos::Coordinat& from,
    const pylos::Coordinat& to);


signals:

  ///PlayerChanged is emitted when the active player has changed
  void PlayerChanged();

private:

  //pylos::QtSprites m_sprites;
  boost::shared_ptr<pylos::Board> m_board;

  ///m_must_remove tracks if the user must remove one/two marbles
  pylos::MustRemoveState m_must_remove;

  ///m_player is the player that is allowed to do a move
  pylos::Player m_player;

};

} //~namespace pylos
} //~namespace ribi

#endif // QTPYLOSBOARDWIDGET_H

 

 

 

 

 

./CppQtPylos/qtpylosboardwidget.cpp

 

//---------------------------------------------------------------------------
/*
PylosWidget, widget to display Pylos class
Copyright (C) 2010-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/ToolTestPylos.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "qtpylosboardwidget.h"

#include <cassert>
#include <cstdlib>
#include <iostream>

#include <boost/numeric/conversion/cast.hpp>

#include <QMouseEvent>
#include <QPainter>

#include "pylosboard.h"
#include "pylosmove.h"
#include "pylosmustremovestate.h"
#include "pylosplayer.h"
#include "trace.h"

#pragma GCC diagnostic pop

ribi::pylos::QtPylosBoardWidget::QtPylosBoardWidget() :
    m_board(new pylos::BoardBasic),
    m_must_remove(pylos::MustRemoveState::no),
    m_player(pylos::Player::player1)
{

}

bool ribi::pylos::QtPylosBoardWidget::CanRemove(const std::vector<pylos::Coordinat>& v) const
{
  return m_board->CanRemove(v,m_player);
}

bool ribi::pylos::QtPylosBoardWidget::CanSet(const pylos::Coordinat& c) const
{
  return m_board->CanSet(c,m_player);
}

bool ribi::pylos::QtPylosBoardWidget::CanSetPlayer(const pylos::Player) const
{
  return m_must_remove == pylos::MustRemoveState::no;
}

bool ribi::pylos::QtPylosBoardWidget::CanTransfer(const pylos::Coordinat& c) const
{
  return m_board->CanTransfer(c,m_player);
}

bool ribi::pylos::QtPylosBoardWidget::CanTransfer(
  const pylos::Coordinat& from,
  const pylos::Coordinat& to) const
{
  return m_board->CanTransfer(from,to,m_player);
}

ribi::pylos::PositionState ribi::pylos::QtPylosBoardWidget::Get(const pylos::Coordinat& c) const
{
  return m_board->Get(c);
}

ribi::pylos::Player ribi::pylos::QtPylosBoardWidget::GetCurrentTurn() const
{
  return m_player;
}

int ribi::pylos::QtPylosBoardWidget::GetLayerSize(const int layer) const
{
  return m_board->GetLayerSize(layer);
}

std::string ribi::pylos::QtPylosBoardWidget::GetVersion() noexcept
{
  return "2.0";
}

std::vector<std::string> ribi::pylos::QtPylosBoardWidget::GetVersionHistory() noexcept
{
  std::vector<std::string> v;
  v.push_back("2010-09-22: version 1.2: initial release version");
  v.push_back("2010-10-06: version 1.3: disallow clicking when there is a winner");
  v.push_back("2010-05-28: version 2.0: inherit from QtPylosWidget");
  return v;
}

ribi::pylos::Winner ribi::pylos::QtPylosBoardWidget::GetWinner() const
{
  return m_board->GetWinner();
}

void ribi::pylos::QtPylosBoardWidget::Remove(const std::vector<pylos::Coordinat>& v)
{
  m_board->Remove(v,m_player);
  m_must_remove = pylos::MustRemoveState::no;
}

void ribi::pylos::QtPylosBoardWidget::Set(const pylos::Coordinat& c)
{
  m_board->Set(c,m_player,m_must_remove);
}

void ribi::pylos::QtPylosBoardWidget::SetPlayer(const pylos::Player player)
{
  assert(CanSetPlayer(player));
  if (m_player != player)
  {
    m_player = player;
    repaint();
    emit PlayerChanged();
  }
}

void ribi::pylos::QtPylosBoardWidget::StartAdvanced()
{
  m_board = pylos::Board::CreateAdvancedBoard();
  m_select = pylos::Coordinat(0,0,0);
  m_other_selectors = std::vector<pylos::Coordinat>();
  repaint();
}

void ribi::pylos::QtPylosBoardWidget::StartBasic()
{
  m_board = pylos::Board::CreateBasicBoard();
  m_select = pylos::Coordinat(0,0,0);
  m_other_selectors = std::vector<pylos::Coordinat>();
  repaint();
}

void ribi::pylos::QtPylosBoardWidget::Transfer(
  const pylos::Coordinat& from,
  const pylos::Coordinat& to)
{
  m_board->Transfer(from,to,m_must_remove);
}

 

 

 

 

 

./CppQtPylos/qtpylosgamewidget.h

 

//---------------------------------------------------------------------------
/*
PylosWidget, widget to display Pylos class
Copyright (C) 2010-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/ToolTestPylos.htm
//---------------------------------------------------------------------------
#ifndef QTPYLOSGAMEWIDGET_H
#define QTPYLOSGAMEWIDGET_H

#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/tuple/tuple.hpp>
#include <boost/shared_ptr.hpp>
#include <QWidget>
#include "qtpyloswidget.h"
#pragma GCC diagnostic pop

struct QPaintEvent;

namespace ribi {
namespace pylos {

struct Game;

///PylosWidget manages a pylos::Game and facilitates its user interface
class QtPylosGameWidget : public QtPylosWidget
{
  Q_OBJECT
public:
  QtPylosGameWidget();
  QtPylosGameWidget(const QtPylosGameWidget&) = delete;
  QtPylosGameWidget& operator=(const QtPylosGameWidget&) = delete;
  ~QtPylosGameWidget() noexcept;

  ///CanRemove specifies if current player can remove one or
  ///two marble(s) at the requested position(s).
  bool CanRemove(const std::vector<pylos::Coordinat>& v) const;

  ///CanSet tests if the current player can be set at the Coordinat
  bool CanSet(const pylos::Coordinat& c) const;

  ///CanTransfer specifies if current player can transfer
  ///the marble at the specified coordinat for movement
  bool CanTransfer(const pylos::Coordinat& c) const;

  ///CanTransfer specifies if current player can transfer his marble
  ///to a new, higher position
  bool CanTransfer(
    const pylos::Coordinat& from,
    const pylos::Coordinat& to) const;

  ///Obtain the PositionState at a certain coordinat
  pylos::PositionState Get(const pylos::Coordinat& c) const;

  ///GetCurrentTurn returns whose turn it is now
  pylos::Player GetCurrentTurn() const;

  ///Obtain the MustRemoveState of the widget
  pylos::MustRemoveState GetMustRemove() const;

  ///GetPylos returns a read-only pylos::Game
  const pylos::Game * GetPylos() { return m_pylos.get(); }

  ///GetLayerSize returns how many marbles this is wide/height.
  ///For exaple; layer 0 has 4x4 marbles, so GetLayerSize
  ///will return 4.
  int GetLayerSize(const int layer) const;

  ///Obtain this class its version
  static std::string GetVersion() noexcept;

  ///Obtain this class its version history
  static std::vector<std::string> GetVersionHistory() noexcept;

  ///Return the possible winner
  pylos::Winner GetWinner() const;

  ///Remove lets the current player remove one or two marbles
  void Remove(const std::vector<pylos::Coordinat>& v);

  ///Set makes current player place his marble
  ///at the specified position. After Set,
  ///GetMustRemove must be called to determine if
  ///the current player must remove some marbles
  void Set(const pylos::Coordinat& c);

  ///StartAdvanced cleans the board to start a game
  ///with advanced rules
  void StartAdvanced();

  ///StartBasic cleans the board to start a game
  ///with basic rules
  void StartBasic();

  ///Transfer lets current player tranfer his marble to a new, higher position
  void Transfer(
    const pylos::Coordinat& from,
    const pylos::Coordinat& to
  );

private:
  ///The pylos::Game class displayed and interacted with
  ///The Game acts as a Model, where this class is a View of
  boost::shared_ptr<pylos::Game> m_pylos;
};

} //~namespace pylos
} //~namespace ribi

#endif // QTPYLOSGAMEWIDGET_H

 

 

 

 

 

./CppQtPylos/qtpylosgamewidget.cpp

 

//---------------------------------------------------------------------------
/*
PylosWidget, widget to display Pylos class
Copyright (C) 2010-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/ToolTestPylos.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "qtpylosgamewidget.h"

#include <cassert>
#include <cstdlib>
#include <iostream>

#include <boost/numeric/conversion/cast.hpp>

#include <QMouseEvent>
#include <QPainter>

#include "pylosboard.h"
#include "pylosgame.h"
#include "pylosmove.h"
#include "pylosmustremovestate.h"
#include "pylosplayer.h"
#include "trace.h"

#pragma GCC diagnostic pop

ribi::pylos::QtPylosGameWidget::QtPylosGameWidget() :
    m_pylos(pylos::Game::CreateBasicGame())
{

}

ribi::pylos::QtPylosGameWidget::~QtPylosGameWidget() noexcept
{
  //OK
}

bool ribi::pylos::QtPylosGameWidget::CanRemove(const std::vector<pylos::Coordinat>& v) const
{
  return m_pylos->CanRemove(v);
}

bool ribi::pylos::QtPylosGameWidget::CanSet(const pylos::Coordinat& c) const
{
  return m_pylos->CanSet(c);
}

bool ribi::pylos::QtPylosGameWidget::CanTransfer(const pylos::Coordinat& c) const
{
  return m_pylos->CanTransfer(c);
}

bool ribi::pylos::QtPylosGameWidget::CanTransfer(
  const pylos::Coordinat& from,
  const pylos::Coordinat& to) const
{
  return m_pylos->CanTransfer(from,to);
}

ribi::pylos::PositionState ribi::pylos::QtPylosGameWidget::Get(const pylos::Coordinat& c) const
{
  return m_pylos->GetBoard()->Get(c);
}

ribi::pylos::Player ribi::pylos::QtPylosGameWidget::GetCurrentTurn() const
{
  return m_pylos->GetCurrentTurn();
}

int ribi::pylos::QtPylosGameWidget::GetLayerSize(const int layer) const
{
  return m_pylos->GetBoard()->GetLayerSize(layer);
}

ribi::pylos::MustRemoveState ribi::pylos::QtPylosGameWidget::GetMustRemove() const
{
  return m_pylos->GetMustRemove();
}

std::string ribi::pylos::QtPylosGameWidget::GetVersion() noexcept
{
  return "2.1";
}

std::vector<std::string> ribi::pylos::QtPylosGameWidget::GetVersionHistory() noexcept
{
  std::vector<std::string> v {
    "2010-09-22: version 1.2: initial release version",
    "2010-10-06: version 1.3: disallow clicking when there is a winner",
    "2010-05-28: version 2.0: inherit from QtPylosWidget",
    "2014-06-20: version 2.1: moved destructor definition to implementation file to solve segmentation fault"
  };
  return v;
}

ribi::pylos::Winner ribi::pylos::QtPylosGameWidget::GetWinner() const
{
  return m_pylos->GetWinner();
}

void ribi::pylos::QtPylosGameWidget::Remove(const std::vector<pylos::Coordinat>& v)
{
  m_pylos->Remove(v);
}

void ribi::pylos::QtPylosGameWidget::Set(const pylos::Coordinat& c)
{
  m_pylos->Set(c);
}

void ribi::pylos::QtPylosGameWidget::StartAdvanced()
{
  m_pylos = pylos::Game::CreateAdvancedGame();
  m_select = pylos::Coordinat(0,0,0);
  m_other_selectors = std::vector<pylos::Coordinat>();
  repaint();
}

void ribi::pylos::QtPylosGameWidget::StartBasic()
{
  m_pylos = pylos::Game::CreateBasicGame();
  m_select = pylos::Coordinat(0,0,0);
  m_other_selectors = std::vector<pylos::Coordinat>();
  repaint();
}

void ribi::pylos::QtPylosGameWidget::Transfer(
  const pylos::Coordinat& from,
  const pylos::Coordinat& to)
{
  m_pylos->Transfer(from,to);
}

 

 

 

 

 

./CppQtPylos/qtpylossprites.h

 

//---------------------------------------------------------------------------
/*
TestPylos, tool to test Pylos class
Copyright (C) 2010-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/ToolTestPylos.htm
//---------------------------------------------------------------------------
#ifndef QTPYLOSSPRITES_H
#define QTPYLOSSPRITES_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include <boost/array.hpp>
#include <QPixmap>
#pragma GCC diagnostic pop

namespace ribi {
namespace pylos {

const boost::array<int,6> GetBlackWhiteColors();
const boost::array<int,6> GetDefaultColors();
const boost::array<int,6> GetRedBlueColors();

struct QtSprites
{
  enum class Type  { player1, player2, player1_select, player2_select, player1_remove, player2_remove, board_bottom, board_hole };

  QtSprites(
    const int board_width = 64,
    const int board_height = 64,
    const boost::array<int,6>& colors = GetDefaultColors())
    : QtSprites(board_width,board_height,colors,board_width/4,board_height/4,64) {}

  ///Get returns the pixmap of a certain sprite
  const QPixmap& Get(const Type sprite) const;

  int GetBoardWidth() const { return m_board_width; }
  int GetBoardHeight() const { return m_board_height; }

  ///Obtain the color scheme
  const boost::array<int,6>& GetColorScheme() const { return m_colors; }

  int GetMarbleWidth() const { return m_board_width / 4; }
  int GetMarbleHeight() const { return m_board_height / 4; }

  ///Obtain this class its version
  static std::string GetVersion() noexcept;

  ///Obtain this class its version history
  static std::vector<std::string> GetVersionHistory() noexcept;

  ///SetBoardSize resizes the sprites to the
  ///required sizes
  //void SetBoardSize(const int board_width, const int board_height);

  ///SetColorScheme sets the color scheme of the Sprites.
  ///This redraws all the sprites.
  //void SetColorScheme(const boost::array<int,6> colors);

  private:
  ///The implementation of the public constructor
  QtSprites(
    const int board_width,
    const int board_height,
    const boost::array<int,6>& colors,
    const int square_width,
    const int square_height,
    const int greyness_hole
    );

  const int m_board_height;
  const int m_board_width;
  const boost::array<int,6> m_colors;
  const QPixmap m_sprite_board_bottom;
  const QPixmap m_sprite_board_hole;
  const QPixmap m_sprite_player1;
  const QPixmap m_sprite_player1_remove;
  const QPixmap m_sprite_player1_select;
  const QPixmap m_sprite_player2;
  const QPixmap m_sprite_player2_remove;
  const QPixmap m_sprite_player2_select;
};

QPixmap DrawBoardBottom(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b);

///From http://www.richelbilderbeek.nl/CppDrawGlobe.htm
QPixmap DrawGlobe(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b);

///From http://www.richelbilderbeek.nl/CppDrawInvertedGlobe.htm
QPixmap DrawInvertedGlobe(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b);

QPixmap DrawRemover(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b);

QPixmap DrawSelector(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b);

//From http://www.richelbilderbeek.nl/CppPaint.htm
void Paint(
  QPixmap& pixmap,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b,
  const unsigned char a = 255); //Opaque

} //~namespace pylos
} //~namespace ribi

#endif // QTPYLOSSPRITES_H

 

 

 

 

 

./CppQtPylos/qtpylossprites.cpp

 

//---------------------------------------------------------------------------
/*
TestPylos, tool to test Pylos class
Copyright (C) 2010-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/ToolTestPylos.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "qtpylossprites.h"
#include <cassert>
#include <boost/numeric/conversion/cast.hpp>
#include <QBitmap>
#include "pylosmove.h"
#pragma GCC diagnostic pop

ribi::pylos::QtSprites::QtSprites(
  const int board_width,
  const int board_height,
  const boost::array<int,6> &colors,
  const int square_width,
  const int square_height,
  const int greyness_hole
  )
  : m_board_height{board_height},
    m_board_width{board_width},
    m_colors(colors),
    m_sprite_board_bottom{DrawBoardBottom(m_board_width,m_board_height,greyness_hole,greyness_hole,greyness_hole)},
    m_sprite_board_hole{DrawInvertedGlobe(square_width,square_height,greyness_hole,greyness_hole,greyness_hole)},
    m_sprite_player1{DrawGlobe(square_width,square_height,m_colors[0],m_colors[1],m_colors[2])},
    m_sprite_player1_remove{DrawRemover(square_width,square_height,m_colors[0],m_colors[1],m_colors[2])},
    m_sprite_player1_select{DrawSelector(square_width,square_height,m_colors[0],m_colors[1],m_colors[2])},
    m_sprite_player2{DrawGlobe(square_width,square_height,m_colors[3],m_colors[4],m_colors[5])},
    m_sprite_player2_remove{DrawRemover(square_width,square_height,m_colors[3],m_colors[4],m_colors[5])},
    m_sprite_player2_select{DrawSelector(square_width,square_height,m_colors[3],m_colors[4],m_colors[5])}
{

}

const QPixmap& ribi::pylos::QtSprites::Get(
  const Type sprite) const
{
  switch (sprite)
  {
    case Type::player1: return m_sprite_player1;
    case Type::player2: return m_sprite_player2;
    case Type::player1_select : return m_sprite_player1_select;
    case Type::player2_select : return m_sprite_player2_select;
    case Type::player1_remove : return m_sprite_player1_remove;
    case Type::player2_remove : return m_sprite_player2_remove;
    case Type::board_bottom   : return m_sprite_board_bottom;
    case Type::board_hole     : return m_sprite_board_hole;
  }
  assert(!"Should not get here");
  throw std::logic_error("ribi::pylos::QtSprites::Get");
}

std::string ribi::pylos::QtSprites::GetVersion() noexcept
{
  return "2.0";
}

std::vector<std::string> ribi::pylos::QtSprites::GetVersionHistory() noexcept
{
  return {
    "2012-05-28: version 2.0: initial release version",
    "2013-09-12: version 2.1: RAII",
  };
}

QPixmap ribi::pylos::DrawBoardBottom(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b)
{
  QPixmap pixmap(width,height);
  Paint(pixmap,r,g,b);
  return pixmap;
}

///From http://www.richelbilderbeek.nl/CppDrawGlobe.htm
QPixmap ribi::pylos::DrawGlobe(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b)
{
  QPixmap pixmap(width,height);
  QImage image = pixmap.toImage();

  assert(image.bytesPerLine() / width == 4
    && "Assume there are 4 bytes per pixel");

  const double r_max = boost::numeric_cast<double>(r);
  const double g_max = boost::numeric_cast<double>(g);
  const double b_max = boost::numeric_cast<double>(b);
  const double midX = boost::numeric_cast<double>(width ) / 2.0;
  const double midY = boost::numeric_cast<double>(height) / 2.0;
  const double max_dist = std::min(midX,midY);

  for (int y=0; y!=height; ++y)
  {

    unsigned char * const line
      = static_cast<unsigned char *>(image.scanLine(y));
    const double y_d = boost::numeric_cast<double>(y);
    for (int x=0; x!=width; ++x)
    {
      const double x_d = boost::numeric_cast<double>(x);
      const double dist
        = std::sqrt(
            ((x_d - midX) * (x_d - midX))
          + ((y_d - midY) * (y_d - midY)) );
      if (dist <= max_dist)
      {
        const double rel_dist = dist / max_dist;
        const int r_here = rel_dist * r_max;
        const int g_here = rel_dist * g_max;
        const int b_here = rel_dist * b_max;
        assert( r_here >= 0);
        assert( r_here < 256);
        assert( g_here >= 0);
        assert( g_here < 256);
        assert( b_here >= 0);
        assert( b_here < 256);
        line[x*4+3] = 255; //Alpha value
        line[x*4+2] = (r_here == 0 ? 1: r_here); //Red
        line[x*4+1] = (g_here == 0 ? 1: g_here); //Green
        line[x*4+0] = (b_here == 0 ? 1: b_here); //Blue
      }
      else
      {
        line[x*4+3] = 0; //Alpha value
        line[x*4+2] = 0; //Red
        line[x*4+1] = 0; //Green
        line[x*4+0] = 0; //Blue
      }
    }
  }
  pixmap = pixmap.fromImage(image);

  //Add transparency
  const QBitmap mask = pixmap.createMaskFromColor(QColor(0,0,0,0).rgb());
  pixmap.setMask(mask);
  return pixmap;
}

///From http://www.richelbilderbeek.nl/CppDrawInvertedGlobe.htm
QPixmap ribi::pylos::DrawInvertedGlobe(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b)
{
  QPixmap pixmap(width,height);
  QImage image = pixmap.toImage();

  assert(image.bytesPerLine() / width == 4
    && "Assume there are 4 bytes per pixel");

  const double r_max = boost::numeric_cast<double>(r);
  const double g_max = boost::numeric_cast<double>(g);
  const double b_max = boost::numeric_cast<double>(b);
  const double midX = boost::numeric_cast<double>(width ) / 2.0;
  const double midY = boost::numeric_cast<double>(height) / 2.0;
  const double max_dist = std::min(midX,midY);

  for (int y=0; y!=height; ++y)
  {

    unsigned char * const line
      = static_cast<unsigned char *>(image.scanLine(y));
    const double y_d = boost::numeric_cast<double>(y);
    for (int x=0; x!=width; ++x)
    {
      const double x_d = boost::numeric_cast<double>(x);
      const double dist
        = std::sqrt(
            ((x_d - midX) * (x_d - midX))
          + ((y_d - midY) * (y_d - midY)) );
      if (dist <= max_dist)
      {
        const double rel_dist = dist / max_dist;
        const int r_here = r_max - (rel_dist * r_max);
        const int g_here = g_max - (rel_dist * g_max);
        const int b_here = b_max - (rel_dist * b_max);
        assert( r_here >= 0);
        assert( r_here < 256);
        assert( g_here >= 0);
        assert( g_here < 256);
        assert( b_here >= 0);
        assert( b_here < 256);
        line[x*4+3] = 255; //Alpha value
        line[x*4+2] = (r_here == 0 ? 1: r_here); //Red
        line[x*4+1] = (g_here == 0 ? 1: g_here); //Green
        line[x*4+0] = (b_here == 0 ? 1: b_here); //Blue
      }
      else
      {
        line[x*4+3] = 0; //Alpha value
        line[x*4+2] = 0; //Red
        line[x*4+1] = 0; //Green
        line[x*4+0] = 0; //Blue
      }
    }
  }
  pixmap = pixmap.fromImage(image);

  //Add transparency
  const QBitmap mask = pixmap.createMaskFromColor(QColor(0,0,0,0).rgb());
  pixmap.setMask(mask);
  return pixmap;
}

QPixmap ribi::pylos::DrawRemover(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b)
{
  //Faded out globe
  QPixmap pixmap(width,height);
  QImage image = pixmap.toImage();

  assert(image.bytesPerLine() / width == 4
    && "Assume there are 4 bytes per pixel");

  const double r_max = boost::numeric_cast<double>(r);
  const double g_max = boost::numeric_cast<double>(g);
  const double b_max = boost::numeric_cast<double>(b);
  const double midX = boost::numeric_cast<double>(width ) / 2.0;
  const double midY = boost::numeric_cast<double>(height) / 2.0;
  const double max_dist = std::min(midX,midY);

  for (int y=0; y!=height; ++y)
  {

    unsigned char * const line
      = static_cast<unsigned char *>(image.scanLine(y));
    const double y_d = boost::numeric_cast<double>(y);
    for (int x=0; x!=width; ++x)
    {
      const double x_d = boost::numeric_cast<double>(x);
      const double dist
        = std::sqrt(
            ((x_d - midX) * (x_d - midX))
          + ((y_d - midY) * (y_d - midY)) );
      if (dist <= max_dist)
      {
        const double rel_dist = dist / max_dist;
        const int r_here = 127 + ((rel_dist * r_max) / 2);
        const int g_here = 127 + ((rel_dist * g_max) / 2);
        const int b_here = 127 + ((rel_dist * b_max) / 2);
        assert( r_here >= 0);
        assert( r_here < 256);
        assert( g_here >= 0);
        assert( g_here < 256);
        assert( b_here >= 0);
        assert( b_here < 256);
        line[x*4+3] = 255; //Alpha value
        line[x*4+2] = (r_here == 0 ? 1: r_here); //Red
        line[x*4+1] = (g_here == 0 ? 1: g_here); //Green
        line[x*4+0] = (b_here == 0 ? 1: b_here); //Blue
      }
      else
      {
        line[x*4+3] = 0; //Alpha value
        line[x*4+2] = 0; //Red
        line[x*4+1] = 0; //Green
        line[x*4+0] = 0; //Blue
      }
    }
  }
  pixmap = pixmap.fromImage(image);

  //Add transparency
  const QBitmap mask = pixmap.createMaskFromColor(QColor(0,0,0,0).rgb());
  pixmap.setMask(mask);
  return pixmap;
}

QPixmap ribi::pylos::DrawSelector(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b)
{
  QPixmap pixmap(width,height);
  QImage image = pixmap.toImage();

  assert(image.bytesPerLine() / width == 4
    && "Assume there are 4 bytes per pixel");

  const double r_max = boost::numeric_cast<double>(r);
  const double g_max = boost::numeric_cast<double>(g);
  const double b_max = boost::numeric_cast<double>(b);
  const double midX = boost::numeric_cast<double>(width ) / 2.0;
  const double midY = boost::numeric_cast<double>(height) / 2.0;
  const double max_dist = std::min(midX,midY);
  const double min_dist = 0.8 * max_dist;

  for (int y=0; y!=height; ++y)
  {

    unsigned char * const line
      = static_cast<unsigned char *>(image.scanLine(y));
    const double y_d = boost::numeric_cast<double>(y);
    for (int x=0; x!=width; ++x)
    {
      const double x_d = boost::numeric_cast<double>(x);
      const double dist
        = std::sqrt(
            ((x_d - midX) * (x_d - midX))
          + ((y_d - midY) * (y_d - midY)) );
      if (dist >= min_dist && dist <= max_dist)
      {
        const double rel_dist = (dist - min_dist) / (max_dist - min_dist);
        const int r_here = rel_dist * r_max;
        const int g_here = rel_dist * g_max;
        const int b_here = rel_dist * b_max;
        assert( r_here >= 0);
        assert( r_here < 256);
        assert( g_here >= 0);
        assert( g_here < 256);
        assert( b_here >= 0);
        assert( b_here < 256);
        line[x*4+3] = 255; //Alpha value
        line[x*4+2] = (r_here == 0 ? 1: r_here); //Red
        line[x*4+1] = (g_here == 0 ? 1: g_here); //Green
        line[x*4+0] = (b_here == 0 ? 1: b_here); //Blue
      }
      else
      {
        line[x*4+3] = 0; //Alpha value
        line[x*4+2] = 0; //Red
        line[x*4+1] = 0; //Green
        line[x*4+0] = 0; //Blue
      }
    }
  }
  pixmap = pixmap.fromImage(image);

  //Add transparency
  const QBitmap mask = pixmap.createMaskFromColor(QColor(0,0,0,0).rgb());
  pixmap.setMask(mask);
  return pixmap;
}

const boost::array<int,6> ribi::pylos::GetBlackWhiteColors()
{
  boost::array<int,6> v;
  v[0] = 255; v[1] = 255; v[2] = 255;
  v[3] =  96; v[4] =  96; v[5] =  96;
  return v;
}

const boost::array<int,6> ribi::pylos::GetDefaultColors()
{
  return GetRedBlueColors();
}

const boost::array<int,6> ribi::pylos::GetRedBlueColors()
{
  boost::array<int,6> v;
  v[0] = 255; v[1] =   0; v[2] =   0;
  v[3] =   0; v[4] =   0; v[5] = 255;
  return v;
}

//From http://www.richelbilderbeek.nl/CppPaint.htm
void ribi::pylos::Paint(
  QPixmap& pixmap,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b,
  const unsigned char a) //Opaque
{
  const int width = pixmap.width();
  const int height = pixmap.height();

  QImage image = pixmap.toImage();

  assert(image.bytesPerLine() / width == 4
    && "Assume there are 4 bytes per pixel");

  for (int y=0; y!=height; ++y)
  {
    unsigned char * const line
      = static_cast<unsigned char *>(image.scanLine(y));
    for (int x=0; x!=width; ++x)
    {
      line[x*4+3] = a; //Alpha value
      line[x*4+2] = r; //Red
      line[x*4+1] = g; //Green
      line[x*4+0] = b; //Blue
    }
  }
  pixmap = pixmap.fromImage(image);
}

 

 

 

 

 

./CppQtPylos/qtpyloswidget.h

 

//---------------------------------------------------------------------------
/*
PylosWidget, widget to display Pylos class
Copyright (C) 2010-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/ToolTestPylos.htm
//---------------------------------------------------------------------------
#ifndef QTPYLOSWIDGET_H
#define QTPYLOSWIDGET_H

#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/tuple/tuple.hpp>
#include <boost/shared_ptr.hpp>

#include <QWidget>

#include "pyloscoordinat.h"
#include "pylosfwd.h"
#include "pylosmove.h"
#include "pyloswinner.h"
//#include "qtpylossprites.h"
#pragma GCC diagnostic pop

struct QPaintEvent;
//namespace Pylos { struct Game; }

namespace ribi {
namespace pylos {

///PylosWidget is the base class of QtPylosBoardWidget and QtPylosWidget
class QtPylosWidget : public QWidget
{
  Q_OBJECT
public:
  QtPylosWidget();
  virtual ~QtPylosWidget() noexcept {}
  ///mouseMoveEvent is public, because
  ///TestPylos must be able to make virtual mouse movements.
  void mouseMoveEvent(QMouseEvent * e);
  ///mousePressEvent is public, because
  ///TestPylos must be able to deliver virtual clicks.
  void mousePressEvent(QMouseEvent*);

  ///CanRemove specifies if current player can remove one or
  ///two marble(s) at the requested position(s).
  virtual bool CanRemove(const std::vector<pylos::Coordinat>& v) const = 0;

  ///CanSet tests if the current player can be set at the Coordinat
  virtual bool CanSet(const pylos::Coordinat& c) const = 0;

  ///CanTransfer specifies if current player can transfer
  ///the marble at the specified coordinat for movement
  virtual bool CanTransfer(const pylos::Coordinat& c) const = 0;

  ///CanTransfer specifies if current player can transfer his marble
  ///to a new, higher position
  virtual bool CanTransfer(
    const pylos::Coordinat& from,
    const pylos::Coordinat& to) const = 0;

  ///GetCurrentTurn returns whose turn it is now
  virtual pylos::Player GetCurrentTurn() const = 0;

  ///GetLayerSize returns how many marbles this is wide/height.
  ///For exaple; layer 0 has 4x4 marbles, so GetLayerSize
  ///will return 4.
  virtual int GetLayerSize(const int layer) const = 0;

  ///MustRemove returns whether the current player
  ///must remove one or two marbles
  virtual pylos::MustRemoveState GetMustRemove() const = 0;

  ///GetOtherSelectors returns the other selectors' current coodinats
  const std::vector<pylos::Coordinat>& GetOtherSelectors() const;

  ///GetSelector returns the selector's current coodinat
  const pylos::Coordinat& GetSelector() const { return m_select; }

  ///Obtain this class its version
  static std::string GetVersion() noexcept;

  ///Obtain this class its version history
  static std::vector<std::string> GetVersionHistory() noexcept;

  ///Return the possible winner
  virtual pylos::Winner GetWinner() const = 0;

  ///Remove lets the current player remove one or two marbles
  virtual void Remove(const std::vector<pylos::Coordinat>& v) = 0;

  ///Set makes current player place his marble
  ///at the specified position. After Set,
  ///GetMustRemove must be called to determine if
  ///the current player must remove some marbles
  virtual void Set(const pylos::Coordinat& c) = 0;

  ///SetColorSchemeBlackWhite sets the color scheme to black and white.
  void SetColorSchemeBlackWhite();

  ///SetColorSchemeRedBlue sets the color scheme to red and blue.
  void SetColorSchemeRedBlue();

  ///SetTilt sets the tilt of this widget
  void SetTilt(const double tilt);

  ///StartAdvanced cleans the board to start a game
  ///with advanced rules
  virtual void StartAdvanced() = 0;

  ///StartBasic cleans the board to start a game
  ///with basic rules
  virtual void StartBasic() = 0;

  ///Transfer lets current player tranfer his marble to a new, higher position
  virtual void Transfer(
    const pylos::Coordinat& from,
    const pylos::Coordinat& to) = 0;


signals:
  ///HasWinner is emitted when a winner is found
  void HasWinner();
  ///SelectorChanged is emitted when the selector is moved
  void SelectorChanged();
  ///DoneMove is emitted when a player has done a successfull move
  void DoneMove();
  ///Toggle is emitted when a marble is (de)selected for something
  void Toggle();

protected:
  ///Draw the Pylos widget
  void paintEvent(QPaintEvent *);

  ///Resize the Pylos widget
  void resizeEvent(QResizeEvent *);

  ///m_other_selectors embodies the coordinats for
  ///- selecting a marble to move to a higher layer
  ///- select one or two marbles for removal
  std::vector<pylos::Coordinat> m_other_selectors;

  ///The current coordinat of the selector
  pylos::Coordinat m_select;

  ///All Pylos sprites
  boost::shared_ptr<const QtSprites> m_sprites;

  ///The angle which the board is tilted in radians.
  ///0.0*M_PI denotes looking at the board from the top
  ///0.5*M_PI denotes looking from directly above the bottom left position
  double m_tilt;

private:
  ///DeselectRemove remove coordinat c from m_other_selectors,
  ///because the player deselected the marble at
  ///that coordinat
  void DeselectRemove(const pylos::Coordinat& c);

  ///DrawRemove draws a marble toggled for removal
  void DrawRemove(QPainter& painter, const pylos::Coordinat& c);

  ///DrawSelect draws the selector
  void DrawSelect(QPainter& painter);

  ///Obtain the PositionState at a certain coordinat
  virtual pylos::PositionState Get(const pylos::Coordinat& c) const = 0;

  ///Obtain all pylos::Coordinat instances at a certain mouse position
  const std::vector<pylos::Coordinat> GetCoordinats(const int mouse_x, const int mouse_y);

  ///From www.richelbilderbeek.nl/CppGetDistance.htm
  static double GetDistance(const double dx, const double dy);

  ///IsOtherSelector returns if the specified coordinat
  ///is selected for removal
  bool IsOtherSelector(const pylos::Coordinat& c) const;

  ///MouseLeftClick handles mouse left-clicking.
  void MouseLeftClick();

  ///MouseLeftClickRemove handles mouse left-clicking
  ///during removal state.
  void MouseLeftClickRemove();

  ///MouseLeftClickSelect handles mouse left-clicking
  ///during select state.
  void MouseLeftClickSelect();

  ///MouseRightClick handles mouse right-clicking.
  void MouseRightClick();

  ///MouseMove is the first member function called after a
  ///mouse move
  void MouseMove(const int x, const int y);

  ///MouseMoveRemoval handles mouse movement
  ///when player must remove one or two marbles
  void MouseMoveRemoval(const int x, const int y);

  ///MouseMoveSelect handles mouse movement
  ///when player must select either a location to
  ///place a new marble or to select a marble to move
  void MouseMoveSelect(const int x, const int y);

  ///SaveAllSprites saves all sprites used in this game.
  void SaveAllSprites() const;

  ///SetSelector sets the selector coordinat to c
  void SetSelector(const pylos::Coordinat& c);

  ///Transform a pylos::Coordinat to a (x,y) position on the widget's canvas
  ///Note: the (x,y) position denotes the center of the marble
  const std::pair<int,int> Transform(const pylos::Coordinat& c) const;
};

} //~namespace pylos
} //~namespace ribi

#endif // QTPYLOSWIDGET_H

 

 

 

 

 

./CppQtPylos/qtpyloswidget.cpp

 

//---------------------------------------------------------------------------
/*
PylosWidget, widget to display Pylos class
Copyright (C) 2010-2015 Richel Bilderbeek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From http://www.richelbilderbeek.nl/ToolTestPylos.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "qtpyloswidget.h"

#include <cassert>
#include <cstdlib>
#include <iostream>

#include <boost/math/constants/constants.hpp>

#include <boost/numeric/conversion/cast.hpp>

#include <QMouseEvent>
#include <QPainter>

#include "pylosboard.h"
#include "pylosgame.h"
#include "pylosmove.h"
#include "pylosmustremovestate.h"
#include "pylosplayer.h"
#include "trace.h"
#include "qtpylossprites.h"
#pragma GCC diagnostic pop

ribi::pylos::QtPylosWidget::QtPylosWidget()
:  QWidget(0),
    m_other_selectors{},
    m_select(0,0,0),
    m_sprites(new QtSprites(this->width(),this->height(),GetRedBlueColors())),
    m_tilt(30.0 * 2.0 * boost::math::constants::pi<double>() / 360.0)
{
  assert(m_sprites);
  //Allows this widget to respond to mouse moving over it
  this->setMouseTracking(true);

  SetSelector(pylos::Coordinat(0,0,0));

  SaveAllSprites();
  this->setMinimumWidth(64);
  this->setMinimumHeight(64);
}

void ribi::pylos::QtPylosWidget::DeselectRemove(const pylos::Coordinat& c)
{
  assert(!m_other_selectors.empty());
  const int sz = boost::numeric_cast<int>(m_other_selectors.size());
  assert(sz == 1 || sz == 2);
  if (sz == 1)
  {
    assert(m_other_selectors[0] == c);
    m_other_selectors.pop_back();
    return;
  }
  assert(sz == 2);
  if (m_other_selectors[0] == c)
  {
    assert(m_other_selectors[1] != c);
    std::swap(m_other_selectors[0],m_other_selectors[1]);
    assert(m_other_selectors.back() == c);
    m_other_selectors.pop_back();
  }
  else
  {
    assert(m_other_selectors[1] == c);
    m_other_selectors.pop_back();
  }
}

void ribi::pylos::QtPylosWidget::DrawRemove(QPainter& painter, const pylos::Coordinat& c)
{
  const pylos::QtSprites::Type sprite =
    ( Get(c) == pylos::PositionState::player1
     ? pylos::QtSprites::Type::player1_remove
     : pylos::QtSprites::Type::player2_remove );

  const std::pair<int,int> p = Transform(c);
  painter.drawPixmap(
    p.first  - (m_sprites->GetMarbleWidth()  / 2),
    p.second - (m_sprites->GetMarbleHeight() / 2),
    m_sprites->Get(sprite));
}

void ribi::pylos::QtPylosWidget::DrawSelect(QPainter& painter)
{
  if (GetWinner() != pylos::Winner::none) return;
  const pylos::QtSprites::Type sprite
    = (GetCurrentTurn() == pylos::Player::player1
    ? pylos::QtSprites::Type::player1_select
    : pylos::QtSprites::Type::player2_select);

  const std::pair<int,int> c = Transform(m_select);
  painter.drawPixmap(
    c.first  - (m_sprites->GetMarbleWidth()  / 2),
    c.second - (m_sprites->GetMarbleHeight() / 2),
    m_sprites->Get(sprite));
}

const std::vector<ribi::pylos::Coordinat> ribi::pylos::QtPylosWidget::GetCoordinats(
  const int mouse_x, const int mouse_y)
{
  const std::vector<pylos::Coordinat> v = pylos::GetAllCoordinats();
  std::vector<double> d; //Distances
  std::transform(v.begin(),v.end(),std::back_inserter(d),
    [this,mouse_x,mouse_y](const pylos::Coordinat& c)
    {
      //Calculate this pylos::Coordinat its center on the widget
      const std::pair<int,int> p = Transform(c);

      return GetDistance(
        static_cast<double>(p.first  - mouse_x),
        static_cast<double>(p.second - mouse_y)
        );
    }
  );
  assert(v.size() == d.size());

  std::vector<pylos::Coordinat> c;

  const std::size_t sz = v.size();
  const double ray = 0.33 * GetDistance(
    static_cast<double>(m_sprites->GetMarbleWidth()),
    static_cast<double>(m_sprites->GetMarbleHeight()) );

  for (std::size_t i=0; i!=sz; ++i)
  {
    if (d[i] < ray) c.push_back(v[i]);
  }
  return c;
}

double ribi::pylos::QtPylosWidget::GetDistance(const double dx, const double dy)
{
  return std::sqrt( (dx * dx) + (dy * dy) );
}

const std::vector<ribi::pylos::Coordinat>& ribi::pylos::QtPylosWidget::GetOtherSelectors() const
{
  return m_other_selectors;
}

std::string ribi::pylos::QtPylosWidget::GetVersion() noexcept
{
  return "1.0";
}

std::vector<std::string> ribi::pylos::QtPylosWidget::GetVersionHistory() noexcept
{
  std::vector<std::string> v;
  v.push_back("2012-05-28: version 1.0: initial version. Added tilt.");
  return v;
}

bool ribi::pylos::QtPylosWidget::IsOtherSelector(const pylos::Coordinat& c) const
{
  return std::find(m_other_selectors.begin(),m_other_selectors.end(),c) != m_other_selectors.end();
}

void ribi::pylos::QtPylosWidget::MouseLeftClick()
{
  if (!GetMustRemove())
    MouseLeftClickSelect();
  else
    MouseLeftClickRemove();
}

void ribi::pylos::QtPylosWidget::MouseLeftClickRemove()
{
  //Player tries to select a third marble
  if (m_other_selectors.size() == 2)
  {
    assert(m_select == m_other_selectors[0] || m_select == m_other_selectors[1]);
    DeselectRemove(m_select);
    repaint();
    emit Toggle();
    return;
  }

  //Toggle marbles selected for removal
  {
    bool must_return = false;
    if (std::find(m_other_selectors.begin(),m_other_selectors.end(),m_select) != m_other_selectors.end())
    {
      //Remove c from m_other_selectors,
      //invalidates d
      DeselectRemove(m_select);
      repaint();
      emit Toggle();
      must_return = true;
    }
    if (must_return) return;
  }

  //Player toggles his first marble for removal
  if (m_other_selectors.empty())
  {
    if (CanRemove( std::vector<pylos::Coordinat>(1,m_select) )) m_other_selectors.push_back(m_select);
    repaint();
    emit Toggle();
    return;
  }

  assert(m_other_selectors.size() == 1);
  //Player clicks a marble and has selected none or one other
  //If the player can remove the selected marble
  //and if he has not selected two marbles
  //for removal already
  if (CanRemove( { m_select,m_other_selectors[0] } ))
  {
    m_other_selectors.push_back(m_select);
    repaint();
    emit Toggle();
  }
}

///MouseLeftClickSelect handles mouse left-clicking
///during select state.
void ribi::pylos::QtPylosWidget::MouseLeftClickSelect()
{
  if (GetWinner() != pylos::Winner::none) return;

  //Select marble for movement
  if (m_other_selectors.empty() && CanTransfer(m_select))
  {
    m_other_selectors.push_back(m_select);
    repaint();
    emit Toggle();
    return;
  }
  //Toggle marble selected for movement
  if (!m_other_selectors.empty() && m_select == m_other_selectors[0])
  {
    m_other_selectors.pop_back();
    repaint();
    emit Toggle();
    return;
  }
  //Add marbles
  if (m_other_selectors.empty() && CanSet(m_select))
  {
    Set(m_select);
    m_other_selectors = std::vector<pylos::Coordinat>();
    repaint();
    emit DoneMove();
    if (GetWinner() != pylos::Winner::none)
      emit HasWinner();
    return;
  }

    //User might want to move a marble
  if (GetMustRemove() == pylos::MustRemoveState::no)
  {
    if (!m_other_selectors.empty()
      && CanTransfer(m_other_selectors[0], m_select) )
    {
      Transfer(m_other_selectors[0],m_select);
      emit DoneMove();
      m_other_selectors = std::vector<pylos::Coordinat>();
      repaint();
    }
    return;
  }
}

void ribi::pylos::QtPylosWidget::MouseMove(const int mouse_x, const int mouse_y)
{
  if (!GetMustRemove())
    MouseMoveSelect(mouse_x,mouse_y);
  else
    MouseMoveRemoval(mouse_x,mouse_y);
}

void ribi::pylos::QtPylosWidget::mouseMoveEvent(QMouseEvent * e)
{
  assert(e->type() == QMouseEvent::MouseMove);
  const int mouse_x = e->x();
  const int mouse_y = e->y();
  MouseMove(mouse_x,mouse_y);
}

void ribi::pylos::QtPylosWidget::mousePressEvent(QMouseEvent* e)
{
  //std::clog << "void ribi::pylos::QtPylosWidget::mousePressEvent(QMouseEvent* e)\n";
  const int mouse_x = e->x();
  const int mouse_y = e->y();
  MouseMove(mouse_x,mouse_y); //Always first perform a mouse move to set the selector right
  switch (e->button())
  {
    case Qt::LeftButton : MouseLeftClick(); break;
    case Qt::RightButton: MouseRightClick(); break;
    default: break;
  }
}

void ribi::pylos::QtPylosWidget::MouseMoveRemoval(
  const int mouse_x,
  const int mouse_y)
{

  //Selector must be set to removable marbles
  const std::vector<pylos::Coordinat> v = GetCoordinats(mouse_x,mouse_y);
  std::for_each(v.begin(),v.end(),
    [this](const pylos::Coordinat& c)
    {
      if (
       //player has selected two marbles for removal,
       //only select those marbles
      (m_other_selectors.size() > 0 && IsOtherSelector(c))
       //player has selected one marble for removal,
       //select the marble (possibly below it) to be
       //removed as well
    || (m_other_selectors.size() == 1 && CanRemove( { m_other_selectors[0],c } ))
       //player has selected nothing for removal
    || (m_other_selectors.empty() && CanRemove( std::vector<pylos::Coordinat>(1,c) ))
      )
      {
        SetSelector(c);
        repaint();
        return;
      }
    }
  );
}

///MouseMoveSelect handles mouse movement
///when player must select either a location to
///place a new marble or to select a marble to move
void ribi::pylos::QtPylosWidget::MouseMoveSelect(
  const int mouse_x, const int mouse_y)
{
  //Selector must show to either
  //- movable marbles
  //- spots to place a new marble
  //Check lowest Pylos level first, otherwise (0,0,0) cannot be selected when (1,0,0) can be
  const std::vector<pylos::Coordinat> v = GetCoordinats(mouse_x,mouse_y);
  std::for_each(v.begin(),v.end(),
    [this](const pylos::Coordinat& c)
    {
      if (
         //Player selects his/her first position
         ( m_other_selectors.empty()
         //Player can set a new marble there at the current empty position
           && (CanSet(c)
         //Or player can select his/her own marbles for transfer
             || CanTransfer(c) ) )
      || (!m_other_selectors.empty()
           && (IsOtherSelector(c)
             || CanTransfer(m_other_selectors[0],c) ) ) )
      {
        SetSelector(c);
        repaint();
        return;
      }
    }
  );
}

void ribi::pylos::QtPylosWidget::MouseRightClick()
{
  if (!GetMustRemove()) return;
  //Right mouse button is only used to remove the
  //marbles selected for removal
  //There must be marbles selected
  if (m_other_selectors.empty()) return;
  //Two marbles are selected
  if (CanRemove(m_other_selectors))
  {
    Remove(m_other_selectors);
    emit DoneMove();
    m_other_selectors = std::vector<pylos::Coordinat>();
    repaint();
  }
}

void ribi::pylos::QtPylosWidget::paintEvent(QPaintEvent *)
{
  //assert(m_pylos);
  QPainter painter(this);

  painter.drawPixmap(0,0,m_sprites->Get(pylos::QtSprites::Type::board_bottom));
  //Draw the hole
  for (int y=0; y!=4; ++y)
    for (int x=0; x!=4; ++x)
      painter.drawPixmap(
        x * m_sprites->GetMarbleWidth(),
        y * m_sprites->GetMarbleHeight(),
        m_sprites->Get(pylos::QtSprites::Type::board_hole));

  for (int layer=0; layer!=4; ++layer)
  {
    const int layer_size = GetLayerSize(layer);
    for (int y=0; y!=layer_size; ++y)
    {
      for (int x=0; x!=layer_size; ++x)
      {
        assert(pylos::Coordinat::IsValid(layer,x,y));
        const pylos::Coordinat c(layer,x,y);

        //Draw selector, after sprite is drawn
        if (c == m_select) DrawSelect(painter);

        const pylos::PositionState state = Get(c);

        pylos::QtSprites::Type sprite = pylos::QtSprites::Type::board_hole;
        switch (state)
        {
          case pylos::PositionState::empty  : continue;
          case pylos::PositionState::player1: sprite = pylos::QtSprites::Type::player1; break;
          case pylos::PositionState::player2: sprite = pylos::QtSprites::Type::player2; break;
          default: assert(!"Should not get here");
        }
        assert(sprite != pylos::QtSprites::Type::board_hole);

        const std::pair<int,int> p = Transform(pylos::Coordinat(layer,x,y));

        painter.drawPixmap(
          p.first  - (m_sprites->GetMarbleWidth()  / 2),
          p.second - (m_sprites->GetMarbleHeight() / 2),
          m_sprites->Get(sprite));

        //Draw remove
        {
          std::for_each(m_other_selectors.begin(),m_other_selectors.end(),
            [this,c,&painter](const pylos::Coordinat& d)
            {
              if (d == c) DrawRemove(painter,c);
            }
          );
        }

        //Draw selector, after sprite is drawn
        if (c == m_select) DrawSelect(painter);
      }
    }
  }
}

void ribi::pylos::QtPylosWidget::resizeEvent(QResizeEvent *)
{
  m_sprites.reset(
    new pylos::QtSprites(
      this->width(),
      this->height(),
      m_sprites->GetColorScheme()
    )
  );
  repaint();
}

void ribi::pylos::QtPylosWidget::SaveAllSprites() const
{
  m_sprites->Get(pylos::QtSprites::Type::player1).save("sprite_player1.png");
  m_sprites->Get(pylos::QtSprites::Type::player2).save("sprite_player2.png");
  m_sprites->Get(pylos::QtSprites::Type::player1_select).save("sprite_player1_select.png");
  m_sprites->Get(pylos::QtSprites::Type::player2_select).save("sprite_player2_select.png");
  m_sprites->Get(pylos::QtSprites::Type::player1_remove).save("sprite_player1_remove.png");
  m_sprites->Get(pylos::QtSprites::Type::player2_remove).save("sprite_player2_remove.png");
  m_sprites->Get(pylos::QtSprites::Type::board_bottom).save("sprite_board_bottom.png");
  m_sprites->Get(pylos::QtSprites::Type::board_hole).save("sprite_board_hole.png");
}

void ribi::pylos::QtPylosWidget::SetColorSchemeBlackWhite()
{
  m_sprites.reset(
    new pylos::QtSprites(
      this->width(),
      this->height(),
      pylos::GetBlackWhiteColors()
    )
  );
  repaint();
}

void ribi::pylos::QtPylosWidget::SetColorSchemeRedBlue()
{
  m_sprites.reset(
    new pylos::QtSprites(
      this->width(),
      this->height(),
      pylos::GetRedBlueColors()
    )
  );
  repaint();
}

void ribi::pylos::QtPylosWidget::SetSelector(const pylos::Coordinat& c)
{
  m_select = c;
  emit SelectorChanged();
}

void ribi::pylos::QtPylosWidget::SetTilt(const double tilt)
{
  m_tilt = tilt;
  repaint();
}

const std::pair<int,int> ribi::pylos::QtPylosWidget::Transform(const pylos::Coordinat& c) const
{
  const int x_co
    = (m_sprites->GetMarbleWidth() / 2)
    + static_cast<int>(std::sin(m_tilt) * static_cast<double>((m_sprites->GetMarbleWidth()) * (c.GetLayer() + 0)))
    + (c.GetX() * m_sprites->GetMarbleWidth());
  const int y_co
    = (m_sprites->GetMarbleHeight() / 2)
    + static_cast<int>(std::sin(m_tilt) * static_cast<double>((m_sprites->GetMarbleHeight()) * (c.GetLayer() + 0)))
    + (c.GetY() * m_sprites->GetMarbleHeight());
  return std::make_pair(x_co,y_co);
}

 

 

 

 

 

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

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml