ヘキサポーン Hexapawn C++
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#define BOARD_SIZE 3
#define SQUARE_COUNT 9
typedef enum _HP_DEFS
{
HPD_NONE,
HPD_BLACK,
HPD_WHITE,
HPD_EMPTY
}HP_DEFS;
class HpPoint
{
public:
int file;
int rank;
public:
HpPoint()
{
file = -1;
rank = -1;
}
HpPoint(int f, int r)
{
file = f;
rank = r;
}
HpPoint Mirror() const
{
HpPoint mirror(file, rank);
if (mirror.file == 0)
mirror.file = 2;
else if (mirror.file == 2)
mirror.file = 0;
return mirror;
}
void ToText(char* pText) const
{
pText[0] = file + 'a';
pText[1] = rank + '1';
pText[2] = 0;
}
};
class HpBoard
{
protected:
HP_DEFS mSquares[BOARD_SIZE][BOARD_SIZE];
public:
HpBoard()
{
for (int file = 0; file < BOARD_SIZE; file++)
{
SetSquare(HpPoint(file, 2), HPD_BLACK);
SetSquare(HpPoint(file, 1), HPD_EMPTY);
SetSquare(HpPoint(file, 0), HPD_WHITE);
}
}
static void GetAllPoints(HpPoint apt[])
{
int n = 0;
for (int rank = 0; rank < BOARD_SIZE; rank++)
{
for (int file = 0; file < BOARD_SIZE; file++)
apt[n++] = HpPoint(file, rank);
}
}
HP_DEFS GetSquare(const HpPoint& pt) const
{
return GetSquare(pt.file, pt.rank);
}
HP_DEFS GetSquare(int file, int rank) const
{
if (0 <= file && file < BOARD_SIZE
&& 0 <= rank && rank < BOARD_SIZE)
{
return mSquares[file][rank];
}
else{
return HPD_NONE;
}
}
void SetSquare(const HpPoint& pt, HP_DEFS pawn)
{
return SetSquare(pt.file, pt.rank, pawn);
}
void SetSquare(int file, int rank, HP_DEFS pawn)
{
if (0 <= file && file < BOARD_SIZE
&& 0 <= rank && rank < BOARD_SIZE)
{
mSquares[file][rank] = pawn;
}
}
void Show() const
{
printf("\n");
for (int rank = BOARD_SIZE - 1; rank >= 0; rank--)
{
printf("\n +---+---+---+");
printf("\n %d |", rank + 1);
for (int file = 0; file < BOARD_SIZE; file++)
{
if (GetSquare(file, rank) == HPD_BLACK)
printf(" ○|");
else if (GetSquare(file, rank) == HPD_WHITE)
printf(" ●|");
else if ((rank % 2) == (file % 2))
printf(":::|");
else
printf(" |");
}
if (rank == 2)
printf(" 7 8 9");
else if (rank == 1)
printf(" 4 5 6");
else if (rank == 0)
printf(" 1 2 3");
}
printf("\n +---+---+---+");
printf("\n a b c\n");
}
bool IsMoveablePawn(const HpPoint& pt)
{
int dir;
int opp;
if (GetSquare(pt) == HPD_WHITE)
{
dir = 1;
opp = HPD_BLACK;
}
else if (GetSquare(pt) == HPD_BLACK)
{
dir = -1;
opp = HPD_WHITE;
}
else{
return false;
}
if (GetSquare(pt.file, pt.rank + dir) == HPD_EMPTY)
return true;
else if (GetSquare(pt.file - 1, pt.rank + dir) == opp)
return true;
else if (GetSquare(pt.file + 1, pt.rank + dir) == opp)
return true;
else
return false;
}
bool IsValidMove(const HpPoint& from, const HpPoint& to)
{
int df = to.file - from.file;
int dr = to.rank - from.rank;
if (GetSquare(from) == HPD_WHITE)
{
if (GetSquare(to) == HPD_EMPTY && df == 0 && dr == 1)
return true;
else if (GetSquare(to) == HPD_BLACK && (df == 1 || df == -1) && dr == 1)
return true;
}
else if (GetSquare(from) == HPD_BLACK)
{
if (GetSquare(to) == HPD_EMPTY && df == 0 && dr == -1)
return true;
else if (GetSquare(to) == HPD_WHITE && (df == 1 || df == -1) && dr == -1)
return true;
}
return false;
}
HP_DEFS CheckFinish(HP_DEFS next)
{
HpPoint all[SQUARE_COUNT];
int cntWhite = 0;
int cntBlack = 0;
for (int file = 0; file < BOARD_SIZE; file++)
{
if (GetSquare(file, BOARD_SIZE - 1) == HPD_WHITE)
return HPD_WHITE;
else if (GetSquare(file, 0) == HPD_BLACK)
return HPD_BLACK;
}
GetAllPoints(all);
for (int sq = 0; sq < SQUARE_COUNT; sq++)
{
if (IsMoveablePawn(all[sq]))
{
if (HPD_WHITE == GetSquare(all[sq]))
cntWhite++;
else if (HPD_BLACK == GetSquare(all[sq]))
cntBlack++;
}
}
if (next == HPD_WHITE && cntWhite == 0)
return HPD_BLACK;
else if (next == HPD_BLACK && cntBlack == 0)
return HPD_WHITE;
return HPD_EMPTY;
}
};
class HpBoardMove : public HpBoard
{
protected:
HpPoint mFrom;
HpPoint mTo;
public:
void SetMove(const HpPoint& rFrom, const HpPoint& rTo)
{
mFrom = rFrom;
mTo = rTo;
}
const HpPoint& GetFrom()
{
return mFrom;
}
const HpPoint& GetTo()
{
return mTo;
}
bool operator ==(const HpBoardMove& bd)const
{
HpPoint all[SQUARE_COUNT];
GetAllPoints(all);
for (int i = 0; i < SQUARE_COUNT; i++)
{
if (this->GetSquare(all[i]) != bd.GetSquare(all[i]))
return false;
}
if (this->mFrom.file != bd.mFrom.file || this->mFrom.rank != bd.mFrom.rank
|| this->mTo.file != bd.mTo.file || this->mTo.rank != bd.mTo.rank)
return false;
return true;
}
void MovePawn()
{
SetSquare(mTo, GetSquare(mFrom));
SetSquare(mFrom, HPD_EMPTY);
}
HpBoardMove MakeMirror() const
{
HpPoint all[SQUARE_COUNT];
HpBoardMove mirror;
mirror.mFrom = mFrom.Mirror();
mirror.mTo = mTo.Mirror();
GetAllPoints(all);
for (int i = 0; i < SQUARE_COUNT; i++)
mirror.SetSquare(all[i], GetSquare(all[i].Mirror()));
return mirror;
}
};
class HpBoardList
{
private:
HpBoardMove* mpBoad;
int mCount;
public:
HpBoardList()
{
mpBoad = NULL;
mCount = 0;
}
~HpBoardList()
{
delete[] mpBoad;
}
void Add(HpBoardMove bd)
{
HpBoardMove* pNewList = new HpBoardMove[mCount + 1];
for (int i = 0; i < mCount; i++)
pNewList[i] = mpBoad[i];
delete[] mpBoad;
mpBoad = pNewList;
mpBoad[mCount++] = bd;
}
bool Exist(const HpBoardMove& rbd) const
{
HpBoardMove mirror = rbd.MakeMirror();
for (int i = 0; i < mCount; i++)
{
if (rbd == mpBoad[i])
return true;
if (mirror == mpBoad[i])
return true;
}
return false;
}
private:
HpBoardList(const HpBoardList&);
};
class Game
{
private:
HpBoardList& mDefeatList;
public:
Game(HpBoardList& rList) : mDefeatList(rList)
{
}
bool MatchBoxTurn(HpBoardMove* pbd, HP_DEFS borw)
{
HpPoint allsq[SQUARE_COUNT];
HpBoard::GetAllPoints(allsq);
for (int i = 0; i < 20; i++)
{
int p = rand() % SQUARE_COUNT;
int q = rand() % SQUARE_COUNT;
if (p != q)
{
HpPoint t = allsq[p];
allsq[p] = allsq[q];
allsq[q] = t;
}
}
for (int i = 0; i < SQUARE_COUNT; i++)
{
if (pbd->GetSquare(allsq[i]) != borw)
continue;
for (int j = 0; j < SQUARE_COUNT; j++)
{
pbd->SetMove(allsq[i], allsq[j]);
if (pbd->IsValidMove(allsq[i], allsq[j]) && !mDefeatList.Exist(*pbd))
{
char szFrom[10];
char szTo[10];
pbd->GetFrom().ToText(szFrom);
pbd->GetTo().ToText(szTo);
printf("\nマッチ箱: %s を %s へ", szFrom, szTo);
return true;
}
}
}
printf("\nリザインします。");
return false;
}
HpPoint InputSquarePoint(char* szGuide)
{
for (;;)
{
printf(szGuide);
int ch = _getche();
switch (ch)
{
case '7':
return HpPoint(0, 2);
case '8':
return HpPoint(1, 2);
case '9':
return HpPoint(2, 2);
case '4':
return HpPoint(0, 1);
case '5':
return HpPoint(1, 1);
case '6':
return HpPoint(2, 1);
case '1':
return HpPoint(0, 0);
case '2':
return HpPoint(1, 0);
case '3':
return HpPoint(2, 0);
}
}
return HpPoint(-1, -1);
}
void PlayerTurn(HpBoardMove* pbd, HP_DEFS borw)
{
HpPoint from, to;
for (;;)
{
from = InputSquarePoint("\n駒を選んでください(1~9):");
if (borw == pbd->GetSquare(from) && pbd->IsMoveablePawn(from))
break;
else
printf("\n動かせる駒がありません");
}
for (;;)
{
to = InputSquarePoint("\nどこに動かしますか?(1~9):");
if (pbd->IsValidMove(from, to))
break;
else
printf("\nそこには動かせません");
}
pbd->SetMove(from, to);
}
};
void main(void)
{
HpBoardList defeats;
HP_DEFS player = HPD_WHITE;
HP_DEFS matchbox = HPD_BLACK;
int reply;
srand((unsigned int)time(0));
do
{
Game game(defeats);
HpBoardMove board;
HpBoardMove lastMatchBoxMove;
int cntMatchBoxMove = 0;
HP_DEFS winner = HPD_NONE;
HP_DEFS turn = HPD_WHITE;
board.Show();
while (winner != HPD_WHITE && winner != HPD_BLACK)
{
if (turn == player)
{
game.PlayerTurn(&board, player);
}
else
{
if (game.MatchBoxTurn(&board, matchbox))
{
lastMatchBoxMove = board;
cntMatchBoxMove++;
}
else
{
winner = player;
break;
}
}
board.MovePawn();
board.Show();
if (turn == HPD_BLACK)
turn = HPD_WHITE;
else
turn = HPD_BLACK;
winner = board.CheckFinish(turn);
}
if (winner == HPD_WHITE)
printf("\n白の勝ちです。\n");
else if (winner == HPD_BLACK)
printf("\n黒の勝ちです。\n");
if (winner != matchbox && cntMatchBoxMove > 0)
defeats.Add(lastMatchBoxMove);
printf("終了する場合は'Q'、続ける場合は他のキーを押してください");
reply = _getche();
} while (!(reply == 'q' || reply == 'Q'));
}