Commit 1027bf8e authored by Jostein Bratlie's avatar Jostein Bratlie

Initial commit: STE6274 Introduction to Technical Programming -- Source Base

parents
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 80
CommentPragmas: '^ \\.+'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
#IncludeCategories:
# - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
# Priority: 2
# - Regex: '^(<|"(gtest|isl|json)/)'
# Priority: 3
# - Regex: '.*'
# Priority: 1
IndentCaseLabels: true
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 10
NamespaceIndentation: All
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 3
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 2
UseTab: Never
...
########################
## Globaly ignored files
*~
*.save
*.bak
*.backup
*.o
*.lib
*.a
*.obj
*.so
*.layout
*.user
*.suo
*.ncb
*.swp
*.moc
*.user*
*.cbp
*.autosave
########
## CMake
CMakeCache.txt
cmake_install.cmake
CMakeFiles/
build/
BUILD/
########
## QMake
*.pro
*.pri
moc_*
#######
## KDev
.kdev4/
*.kdev4
##########################################
# Ignored Ct Creator spesifics directories
qtc-gdbmacros
cmake_minimum_required(VERSION 3.8)
# Project name
project(my_board_game VERSION 0.1 LANGUAGES CXX)
# Protect Wintendo
if(MSVC AND NOT VCPKG_TOOLCHAIN)
message(FATAL_ERROR
"Enable VCPKG toolchain on MSVC platform\n"
" Star over; CMAKE_TOOLCHAIN_FILE definition missing!\n"
" i.e.: cmake -DCMAKE_TOOLCHAIN_FILE=<path_to>\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake <path_to>\\source\\"
)
endif()
## Global compiler spesific compile options
SET(CLANG_COMPILE_OPTIONS
-Weverything -pedantic -Werror
-Wno-c++98-compat -Wno-c++98-compat-pedantic
-Wno-documentation
-Wno-global-constructors
-Wno-exit-time-destructors
-Wno-weak-vtables
-Wno-padded
-Wno-unused-parameter
-Wno-language-extension-token
-Wno-extra-semi-stmt
)
SET(GCC_COMPILE_OPTIONS
-pedantic -Wall -Werror
)
SET(MSVC_COMPILE_OPTIONS
/Wall /WX /Za
)
# Include engine to build
add_subdirectory(libs/engine)
# Include qtclient to build
option(BUILD_QTCLIENT "Whether or not to build the Qt client!" ON)
if(BUILD_QTCLIENT)
add_subdirectory(qtclient)
endif(BUILD_QTCLIENT)
# Include unittests to build
option(BUILD_UNITTESTS "Whether or not to build unit tests!" OFF)
if(BUILD_UNITTESTS)
add_subdirectory(tools/testing)
endif(BUILD_UNITTESTS)
# Include benchmarks to build
option(BUILD_BENCHMARKS "Whether or not to build benchmarks!" ON)
if(BUILD_BENCHMARKS)
add_subdirectory(tools/benchmark)
endif(BUILD_BENCHMARKS)
cmake_minimum_required(VERSION 3.8)
### Setup qtclient project
project(engine VERSION 0.1 LANGUAGES CXX)
# interface part of engine library
SET(IF_PROJECT_NAME ${PROJECT_NAME}_interface)
add_library(${IF_PROJECT_NAME} INTERFACE)
# engine library (build static on Windows MSVC)
if(MSVC)
add_library(${PROJECT_NAME} STATIC)
else()
add_library(${PROJECT_NAME} SHARED)
endif()
###########################
# Compiler spesific options
message("Clang compile options: ${CLANG_COMPILE_OPTIONS}")
message("GCC compile options: ${GCC_COMPILE_OPTIONS}")
message("MSVC compile options: ${MSVC_COMPILE_OPTIONS}")
## INTERFACE
# Turn on c++17 compile features -- minimum CMake Version 3.8 required
target_compile_features(${IF_PROJECT_NAME}
INTERFACE $<$<CXX_COMPILER_ID:Clang>:cxx_std_17>
INTERFACE $<$<CXX_COMPILER_ID:GNU>:cxx_std_17>
INTERFACE $<$<CXX_COMPILER_ID:MSVC>:cxx_std_17>
)
# Compile definitions
target_compile_definitions( ${IF_PROJECT_NAME}
INTERFACE $<$<CXX_COMPILER_ID:MSVC>: _USE_MATH_DEFINES>
)
# Comple options
target_compile_options(${IF_PROJECT_NAME}
INTERFACE $<$<CXX_COMPILER_ID:Clang>: ${CLANG_COMPILE_OPTIONS}>
INTERFACE $<$<CXX_COMPILER_ID:GNU>: ${GCC_COMPILE_OPTIONS}>
INTERFACE $<$<CXX_COMPILER_ID:MSVC>: ${MSVC_COMPILE_OPTIONS}>
)
## ENGINE
# Turn on c++17 compile features -- minimum CMake Version 3.8 required
target_compile_features(${PROJECT_NAME}
PUBLIC $<$<CXX_COMPILER_ID:Clang>:cxx_std_17>
PUBLIC $<$<CXX_COMPILER_ID:GNU>:cxx_std_17>
PUBLIC $<$<CXX_COMPILER_ID:MSVC>:cxx_std_17>
)
# Compile definitions
target_compile_definitions( ${PROJECT_NAME}
PUBLIC $<$<CXX_COMPILER_ID:MSVC>: _USE_MATH_DEFINES>
)
# Comple options
target_compile_options(${PROJECT_NAME}
PUBLIC $<$<CXX_COMPILER_ID:Clang>: ${CLANG_COMPILE_OPTIONS}>
PUBLIC $<$<CXX_COMPILER_ID:GNU>: ${GCC_COMPILE_OPTIONS}>
PUBLIC $<$<CXX_COMPILER_ID:MSVC>: ${MSVC_COMPILE_OPTIONS}>
)
# Turn off platform-spesific extensions
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_EXTENSIONS OFF)
############################
# Target sources and friends
# Headers
target_include_directories( ${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
)
# Source (translation units)
SET(SOURCE_PREFIX source)
target_sources( ${PROJECT_NAME} PRIVATE
${SOURCE_PREFIX}/mygameengine.cpp
${SOURCE_PREFIX}/orangemonkey_ai.cpp
${SOURCE_PREFIX}/utility.cpp
)
##################################
# Export targets and configuration
export( TARGETS ${PROJECT_NAME}
NAMESPACE ${PROJECT_NAME}::
FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}-targets.cmake"
)
# Add alias gmlib2::${PROJECT_NAME} to ${PROJECT_NAME} such that we can reference this
# in the same way as for other consumer usages (external library)
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
include(CMakeFindDependencyMacro)
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
message(STATUS "Found @PROJECT_NAME@")
#ifndef BASIC_TYPES_H
#define BASIC_TYPES_H
// stl
#include <bitset>
#include <array>
#include <vector>
#include <set>
#include <unordered_set>
#include <utility>
#include <memory>
#include <chrono>
namespace gameengine
{
// 8x8 game board
namespace detail
{
constexpr size_t computeBoardSize() { return 8 * 8; }
constexpr size_t invalidBoardPosition() { return computeBoardSize() + 1; }
} // namespace detail
struct BitPos {
constexpr BitPos() : m_bitpos{detail::invalidBoardPosition()} {}
constexpr explicit BitPos(size_t bitpos) : m_bitpos{bitpos} {}
constexpr explicit BitPos(int bitpos) : m_bitpos{size_t(bitpos)} {}
BitPos(const BitPos&) = default;
BitPos& operator=(const BitPos& o)
{
m_bitpos = o.m_bitpos;
return *this;
}
static constexpr BitPos invalid()
{
return BitPos{detail::invalidBoardPosition()};
}
constexpr size_t value() const { return m_bitpos; }
constexpr bool isValid() const
{
return m_bitpos not_eq detail::invalidBoardPosition();
}
constexpr bool operator<(const BitPos& other) const
{
return m_bitpos < other.m_bitpos;
}
constexpr bool operator==(const BitPos& other) const
{
return m_bitpos == other.m_bitpos;
}
constexpr bool operator!=(const BitPos& other) const
{
return !(*this == other);
}
private:
size_t m_bitpos;
};
enum class MoveDirection { N, S, E, W, NE, NW, SE, SW };
} // namespace gameengine
namespace std
{
template <>
struct hash<gameengine::BitPos> {
size_t operator()(const gameengine::BitPos& bitpos) const
{
return std::hash<size_t>{}(bitpos.value());
}
};
} // END namespace std
namespace gameengine // resume namespace gameengine
{
using BitPieces = std::bitset<detail::computeBoardSize()>;
using BitBoard = std::array<BitPieces, 2>;
enum class PlayerId : size_t { One = 0, Two };
enum class PlayerType { Human, AI };
using PlayerIdSet = std::set<PlayerId>;
using BitPosSet = std::unordered_set<BitPos>;
} // namespace gameengine
#endif // BASIC_TYPES_H
#ifndef GAMEENGINE_INTERFACE_H
#define GAMEENGINE_INTERFACE_H
#include "basic_types.h"
#include "player_interface.h"
// stl
#include <memory>
#include <iostream>
namespace gameengine
{
namespace detail
{
struct PlayerStruct {
std::unique_ptr<PlayerInterface> obj;
PlayerType type;
};
} // namespace detail
class GameEngineInterface {
public:
GameEngineInterface() = default;
virtual ~GameEngineInterface() = default;
/*! Init a new game for the set players */
virtual bool initNewGame() = 0;
/*! End and reset the game object to a clean state */
virtual void clearGame() = 0;
template <typename Player_T, PlayerId PlayerId_T, typename... PlayerArg_Ts>
void initPlayerType(PlayerArg_Ts... player_args)
{
static_assert(
std::is_base_of<HumanPlayer, Player_T>::value
or std::is_base_of<AIInterface, Player_T>::value,
"Player class must be of either HumanPlayer or AIInterface base.");
const auto player_type = std::is_base_of<HumanPlayer, Player_T>::value
? PlayerType::Human
: PlayerType::AI;
if constexpr (PlayerId(PlayerId_T) == PlayerId::One) {
std::cout << "Hello player one!" << std::endl;
m_player_one.obj
= std::make_unique<Player_T>(PlayerId::One, player_args...);
m_player_one.type = player_type;
}
else {
std::cout << "Hello player two!" << std::endl;
m_player_two.obj
= std::make_unique<Player_T>(PlayerId::Two, player_args...);
m_player_two.type = player_type;
}
}
/*! Perform a move for the current HUMAN player
* \param[in] move What move to perform
* \return Returns true if a move was successfully made */
virtual bool performMoveForCurrentHuman(const BitPos& move) = 0;
/*! Enqueue thinking for the current player
* \param[in] max_time The time awailable for thinking */
virtual void think(const std::chrono::seconds& max_time) = 0;
/*! Return the player id of the current player */
virtual PlayerId currentPlayerId() const = 0;
/*! Return the player type of the current player */
virtual PlayerType currentPlayerType() const = 0;
/*! Query the bitboard piece position set of a given player
* \param[in] player_id The given player
* \return The current bitboard piece position set of the player */
virtual BitPieces pieces(const PlayerId& player_id) const = 0;
/*! Query the complete bitboard piece set for the current game position. */
virtual const BitBoard& board() const = 0;
protected:
BitBoard m_board; /*< BitBoard holding player piece positions */
detail::PlayerStruct m_player_one;
detail::PlayerStruct m_player_two;
};
} // namespace gameengine
#endif // GAMEENGINE_INTERFACE_H
#ifndef PLAYER_INTERFACE_H
#define PLAYER_INTERFACE_H
#include "basic_types.h"
namespace gameengine
{
class PlayerInterface {
public:
explicit PlayerInterface() = default;
virtual ~PlayerInterface() = default;
/*! Ask the player to think ^^,
* \param[in] pieces The current piece position bitboard
* \param[in] goals The goal piece position bitboard
* \param[in] player_id The current player id to think for
* \param[in] max_time The time awailable for thinking
*/
virtual void think(const BitBoard& pieces, const PlayerId& player_id,
const std::chrono::seconds& max_time)
= 0;
/*! Query the best move after decided by the player */
virtual BitPos bestMove() const = 0;
/*! Query the player type {humen or A.I.} */
virtual PlayerType type() const = 0;
};
class HumanPlayer final : public PlayerInterface {
public:
HumanPlayer(const PlayerId&) {}
/*! Specialication of the think method for humans
* We like to think on our own
* This statement can not be modified */
void think(const BitBoard&, const PlayerId&,
const std::chrono::seconds&) override final
{
}
/*! Specialication of the best move method for humans
* No-one needs to know what I think is the best move */
BitPos bestMove() const override final { return {}; }
/*! Specialication of the type function returning the player type */
PlayerType type() const override final { return PlayerType::Human; }
};
class AIInterface : public PlayerInterface {
public:
/*! Specialication of the type function returning the player type */
PlayerType type() const override final { return PlayerType::AI; }
};
} // namespace gameengine
#endif // PLAYER_INTERFACE_H
#ifndef UTILITY_INTERFACE_H
#define UTILITY_INTERFACE_H
#include "basic_types.h"
namespace gameengine::utility
{
// Board validation
/*! Query a a bitboard piece position set representing all players pieces
* for a given BitBoard */
BitPieces occupiedPositions(const BitBoard& board);
/*! Query whether a position on a bitboard piece position set is occupied
* \param[in] pieces A players pieces on the board
* \param[in] board_pos The board position
* \return Returns true if the queried position is occupied */
bool occupied(const BitPieces& pieces, const BitPos& board_pos);
/*! Query whether a position on a bitboard is occupied
* \param[in] board The board
* \param[in] board_pos The board position
* \return Returns true if the queried position is occupied */
bool occupied(const BitBoard& board, const BitPos& board_pos);
/*! Query the next board position given a direction
* \param[in] board_pos Board position of search start
* \param[in] dir Search direction
* \return Returns the next position */
BitPos nextPosition(const BitPos& board_pos, const MoveDirection& dir);
/*! Query a players legal moves
* \param[in] board The board
* \param[in] player_id Querying player's id
* \return Set of legal moves */
BitPosSet legalMoves(const BitBoard& board, const PlayerId& player_id);
/*! Query wherther a move for a given player is legal for a given bitboard
* \param[in] board The board
* \param[in] player_id The player id
* \param[in] board_pos The board position where the next piece is to be
* placed
* \return Returns true if the move is legal */
bool isLegalMove(const BitBoard& board, const PlayerId&,
const BitPos& board_pos);
/*! Perform a move on a given board for current player id and valid board
* position
* \param[in,out] board Bit board
* \param[in] player_id Current player
* \param[in board_pos Valid piece placement */
void move(BitBoard& board, const PlayerId& player_id,
const BitPos& board_pos);
} // namespace gameengine::utility
#endif // UTILITY_INTERFACE_H