ヘキサポーン 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
{
NONE,
BLACK,
WHITE,
EMPTY
}HP_DEFS;
typedef enum _HP_BOOL
{
HP_FALSE = 0,
HP_TRUE = 1
}HP_BOOL;
typedef struct
{
int file;
int rank;
} HP_POINT;
typedef struct
{
HP_DEFS squares[BOARD_SIZE][BOARD_SIZE];
HP_POINT from;
HP_POINT to;
} HP_BOARD;
HP_POINT Point(int file, int rank)
{
HP_POINT pt;
pt.file = file;
pt.rank = rank;
return pt;
}
HP_DEFS GetSquare(HP_BOARD board, HP_POINT pt)
{
if (0 <= pt.file && pt.file < BOARD_SIZE
&& 0 <= pt.rank && pt.rank < BOARD_SIZE)
{
return board.squares[pt.file][pt.rank];
}
else{
return NONE;
}
}
void SetSquare(HP_BOARD* pboard, HP_POINT pt, HP_DEFS pawn)
{
if (0 <= pt.file && pt.file < BOARD_SIZE
&& 0 <= pt.rank && pt.rank < BOARD_SIZE)
{
pboard->squares[pt.file][pt.rank] = pawn;
}
}
void InitializeBoard(HP_BOARD* pboard)
{
int file;
for (file = 0; file < BOARD_SIZE; file++)
{
SetSquare(pboard, Point(file, 2), BLACK);
SetSquare(pboard, Point(file, 1), EMPTY);
SetSquare(pboard, Point(file, 0), WHITE);
}
}
void GetAllPoints(HP_POINT apt[])
{
int file, rank;
int n = 0;
for (rank = 0; rank < BOARD_SIZE; rank++)
{
for (file = 0; file < BOARD_SIZE; file++)
apt[n++] = Point(file, rank);
}
}
HP_BOOL CompareBoard(HP_BOARD bd1, HP_BOARD bd2)
{
HP_POINT all[SQUARE_COUNT];
int i;
GetAllPoints(all);
for (i = 0; i < SQUARE_COUNT; i++)
{
if (GetSquare(bd1, all[i]) != GetSquare(bd2, all[i]))
return HP_FALSE;
}
if (bd1.from.file != bd2.from.file || bd1.from.rank != bd2.from.rank
|| bd1.to.file != bd2.to.file || bd1.to.rank != bd2.to.rank)
return HP_FALSE;
return HP_TRUE;
}
void ShowBoard(HP_BOARD bd)
{
int rank, file;
printf("\n");
for (rank = BOARD_SIZE-1; rank >= 0 ; rank--)
{
printf("\n +---+---+---+");
printf("\n %d |", rank + 1);
for (file = 0; file < BOARD_SIZE; file++)
{
if (GetSquare(bd, Point(file, rank)) == BLACK)
printf(" ○|");
else if (GetSquare(bd, Point(file, rank)) == 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");
}
HP_BOOL IsMoveablePawn(HP_BOARD bd, HP_POINT pt)
{
int dir;
int opp;
if (GetSquare(bd, pt) == WHITE)
{
dir = 1;
opp = BLACK;
}
else if (GetSquare(bd, pt) == BLACK)
{
dir = -1;
opp = WHITE;
}
else{
return HP_FALSE;
}
if (GetSquare(bd, Point(pt.file, pt.rank + dir)) == EMPTY)
return HP_TRUE;
else if (GetSquare(bd, Point(pt.file - 1, pt.rank + dir)) == opp)
return HP_TRUE;
else if (GetSquare(bd, Point(pt.file + 1, pt.rank + dir)) == opp)
return HP_TRUE;
else
return HP_FALSE;
}
HP_BOOL IsValidMove(HP_BOARD bd)
{
int df = bd.to.file - bd.from.file;
int dr = bd.to.rank - bd.from.rank;
if (GetSquare(bd, bd.from) == WHITE)
{
if (GetSquare(bd, bd.to) == EMPTY && df == 0 && dr == 1)
return HP_TRUE;
else if (GetSquare(bd, bd.to) == BLACK && (df == 1 || df == -1) && dr == 1)
return HP_TRUE;
}
else if (GetSquare(bd, bd.from) == BLACK)
{
if (GetSquare(bd, bd.to) == EMPTY && df == 0 && dr == -1)
return HP_TRUE;
else if (GetSquare(bd, bd.to) == WHITE && (df == 1 || df == -1) && dr == -1)
return HP_TRUE;
}
return HP_FALSE;
}
void ToFileRankText(char* pText, HP_POINT pt)
{
pText[0] = pt.file + 'a';
pText[1] = pt.rank + '1';
pText[2] = 0;
}
HP_POINT ConvertMirror(HP_POINT pt)
{
if (pt.file == 0)
pt.file = 2;
else if (pt.file == 2)
pt.file = 0;
return pt;
}
void DumpMem(HP_BOARD mem)
{
int i, j;
char from[10];
char to[10];
printf("\n");
for (i = BOARD_SIZE - 1; i >= 0; i--){
for (j = 0; j < BOARD_SIZE; j++)
{
printf("%c", GetSquare(mem, Point(j, i)));
}
printf(" ");
}
ToFileRankText(from, mem.from);
ToFileRankText(to, mem.to);
printf(" %s → %s", from, to);
}
HP_BOOL FindDefeat(HP_BOARD bd, HP_BOARD aDefeat[], int cntDefeat)
{
HP_POINT all[SQUARE_COUNT];
HP_BOARD mirror;
int i;
GetAllPoints(all);
mirror.from = ConvertMirror(bd.from);
mirror.to = ConvertMirror(bd.to);
for (i = 0; i < SQUARE_COUNT; i++)
SetSquare(&mirror, all[i], GetSquare(bd, ConvertMirror(all[i])));
for (i = 0; i < cntDefeat; i++)
{
if (CompareBoard(bd, aDefeat[i]))
return HP_TRUE;
if (CompareBoard(mirror, aDefeat[i]))
return HP_TRUE;
}
return HP_FALSE;
}
HP_BOOL MatchBoxTurn(HP_BOARD* pbd, HP_DEFS borw, HP_BOARD aDef[], int cntDef)
{
HP_POINT allsq[SQUARE_COUNT];
int i, j;
GetAllPoints(allsq);
for (i = 0; i < 20; i++)
{
int p = rand() % SQUARE_COUNT;
int q = rand() % SQUARE_COUNT;
if (p != q)
{
HP_POINT t = allsq[p];
allsq[p] = allsq[q];
allsq[q] = t;
}
}
for (i = 0; i < SQUARE_COUNT; i++)
{
if (GetSquare(*pbd, allsq[i]) != borw)
continue;
for (j = 0; j < SQUARE_COUNT; j++)
{
pbd->from = allsq[i];
pbd->to = allsq[j];
if (IsValidMove(*pbd) && !FindDefeat(*pbd, aDef, cntDef))
{
char szFrom[10];
char szTo[10];
ToFileRankText(szFrom, pbd->from);
ToFileRankText(szTo, pbd->to);
printf("\nマッチ箱: %s を %s へ", szFrom, szTo);
return HP_TRUE;
}
}
}
printf("\nリザインします。");
return HP_FALSE;
}
HP_POINT InputSquarePoint( char* szGuide)
{
for (;;)
{
int ch;
printf(szGuide);
ch = _getche();
switch (ch)
{
case '7':
return Point(0, 2);
case '8':
return Point(1, 2);
case '9':
return Point(2, 2);
case '4':
return Point(0, 1);
case '5':
return Point(1, 1);
case '6':
return Point(2, 1);
case '1':
return Point(0, 0);
case '2':
return Point(1, 0);
case '3':
return Point(2, 0);
}
}
return Point(-1, -1);
}
void PlayerTurn(HP_BOARD* pbd, HP_DEFS borw)
{
for (;;)
{
pbd->from = InputSquarePoint("\n駒を選んでください(1~9):");
if (borw == GetSquare(*pbd, pbd->from) && IsMoveablePawn(*pbd, pbd->from))
break;
else
printf("\n動かせる駒がありません");
}
for (;;)
{
pbd->to = InputSquarePoint("\nどこに動かしますか?(1~9):");
if (IsValidMove(*pbd))
break;
else
printf("\nそこには動かせません");
}
}
HP_DEFS CheckFinish(HP_BOARD bd, HP_DEFS next)
{
HP_POINT all[SQUARE_COUNT];
int file, sq;
int cntWhite = 0;
int cntBlack = 0;
for (file = 0; file < BOARD_SIZE; file++)
{
if (GetSquare(bd, Point(file, BOARD_SIZE - 1)) == WHITE)
return WHITE;
else if (GetSquare(bd, Point(file, 0)) == BLACK)
return BLACK;
}
GetAllPoints(all);
for (sq = 0; sq < SQUARE_COUNT; sq++)
{
if (IsMoveablePawn(bd, all[sq]))
{
if (WHITE == GetSquare(bd, all[sq]))
cntWhite++;
else if (BLACK == GetSquare(bd, all[sq]))
cntBlack++;
}
}
if (next == WHITE && cntWhite == 0)
return BLACK;
else if (next == BLACK && cntBlack == 0)
return WHITE;
return EMPTY;
}
void main(void)
{
HP_BOARD aDefeat[30];
int cntDefeat = 0;
HP_DEFS player = WHITE;
HP_DEFS matchbox = BLACK;
int reply;
srand((unsigned int)time(0));
do
{
HP_BOARD board;
HP_BOARD lastMatchBoxMove;
int cntMatchBoxMove = 0;
HP_DEFS winner = NONE;
HP_DEFS turn = WHITE;
InitializeBoard(&board);
ShowBoard(board);
while (winner != WHITE && winner != BLACK)
{
if (turn == player)
{
PlayerTurn(&board, player);
}
else
{
if (MatchBoxTurn(&board, matchbox, aDefeat, cntDefeat))
{
lastMatchBoxMove = board;
cntMatchBoxMove++;
}
else
{
winner = player;
break;
}
}
SetSquare(&board, board.to, GetSquare(board, board.from));
SetSquare(&board, board.from, EMPTY);
ShowBoard(board);
if (turn == BLACK)
turn = WHITE;
else
turn = BLACK;
winner = CheckFinish(board, turn);
}
if (winner == WHITE)
printf("\n白の勝ちです。\n");
else if (winner == BLACK)
printf("\n黒の勝ちです。\n");
if (winner != matchbox && cntMatchBoxMove > 0)
aDefeat[cntDefeat++] = lastMatchBoxMove;
printf("終了する場合は'Q'、続ける場合は他のキーを押してください");
reply = _getche();
} while (!(reply == 'q' || reply == 'Q'));
}