`
https://github.com/jjw712/my_chess_0709.git
Board() // 게임판 초기상태로 생성
↓
ChessDisplay() // 게임판의 현재 상태 출력
↓
GetCommand() // 입력 커멘드에 따라 행동
↓
MoveTo() // 가능한 입력의 경우 말 이동 후 ChessDisplay() 단계 부터 반복
실제 플레이는 class ChessPlay 에서 실행
#include <iostream>
#include "Let_Play.h"
using namespace std;
/// Board() -> 게임판
/// 구조체 Pieces -> 각 말의 정보,
/// MoveTo() -> 각각의 말들의 이동
/// display() -> 현재 게임판의 상태 표시
///
/// Board생성 후 매턴(command->move->display) 반복
int main() {
ChessPlay Play = ChessPlay();
Play.~ChessPlay();
printf("main\n");
return 0;
}
-> class ChessBoard 의 멤버함수들을 순서에 맞게 실행
#pragma once
#include"Board.h"
class ChessBoard;
class ChessPlay {
private :
public:
ChessPlay();
~ChessPlay();
};
-> 이동 출력 등의 실제 기능 구현
#pragma once
#include<stdio.h>
typedef struct Piece { // 각 말의 정보
int type; // 1 Pawn 2 Rock 3 Knight 4 bishop 5 Queen 6 King
int team; // 0 black 1 white
}Piece;
static Piece pBoard[10][10] = { 0, }; //게임판 정의
/* 0 1 2 3 4 5 6 7 8 9
0 -1-1-1-1-1-1-1-1-1-1
1 -1 -1
2 -1 -1
3 -1 -1
4 -1 -1
5 -1 -1
6 -1 -1
7 -1 -1
8 -1 -1
9 -1-1-1-1-1-1-1-1-1-1
*/
class ChessBoard {
private:
public:
ChessBoard(Piece _pBoard[][10]);
Piece* ChessDisplay(Piece _pBoard[][10], int _turn);
int MoveTo(int ax, int ay, int bx, int by, Piece _pBoard[][10]);
// int GetCommand(Piece _pBoard[][10]);
int GetCommand2(Piece _pBoard[][10], int* _turn);
~ChessBoard() {
}
};
1. 초기 플레이보드 생성 후 (화면 출력 -> 커멘드 입력) 게임 종료 혹은 재시작 입력까지 무한반복
2. 이동 성공시 게임의 턴수 증가
#include "Let_Play.h"
#include<iostream>
ChessPlay::ChessPlay() {
ChessBoard Board = ChessBoard(pBoard);
int turn = 1;
while (1) {
Board.ChessDisplay(pBoard,turn);
int tmp = Board.GetCommand2(pBoard, &turn);
if (tmp >= 1)
turn++;
}
}
ChessPlay::~ChessPlay() {
}
1. 초기상태의 플레이보드 생성
#include <Windows.h>
#include "Board.h"
#define _MAX(a, b) (((a) > (b)) ? (a) : (b))
ChessBoard::ChessBoard(Piece _pBoard[][10]){ // (종류, 팀)
Piece out = { -1,-1 };
Piece empty = { 0,-1 };
Piece B_Pawn = { 1,0 };
Piece W_Pawn = { 1,1 };
Piece B_Rock = { 2,0 };
Piece W_Rock = { 2,1 };
Piece B_Knight = { 3,0 };
Piece W_Knight = { 3,1 };
Piece B_Bishop = { 4,0 };
Piece W_Bishop = { 4,1 };
Piece B_Queen = { 5,0 };
Piece W_Queen = { 5,1 };
Piece B_King = { 6,0 };
Piece W_King = { 6,1 };
for (int y = 0; y <= 9; y++) {
for (int x = 0; x <= 9; x++) {
_pBoard[y][x] =empty;
}
}
// if (start == true) { // 처음
for (int i = 0; i <= 9; i++) {
_pBoard[i][0] = out;
_pBoard[i][9] = out;
_pBoard[0][i] = out;
_pBoard[9][i] = out;
}
for (int x = 1; x <= 8;x++) {
_pBoard[2][x] = W_Pawn;
_pBoard[7][x] = B_Pawn;
}
_pBoard[1][1] = W_Rock;
_pBoard[1][8] = W_Rock;
_pBoard[8][1] = B_Rock;
_pBoard[8][8] = B_Rock;
_pBoard[1][2] = W_Knight;
_pBoard[1][7] = W_Knight;
_pBoard[8][2] = B_Knight;
_pBoard[8][7] = B_Knight;
_pBoard[1][3] = W_Bishop;
_pBoard[1][6] = W_Bishop;
_pBoard[8][3] = B_Bishop;
_pBoard[8][6] = B_Bishop;
_pBoard[1][4] = W_King;
_pBoard[1][5] = W_Queen;
_pBoard[8][4] = B_King;
_pBoard[8][5] = B_Queen;
for (int i = 0; i <= 9; i++) {
for (int j = 0; j <= 9; j++) {
if (_pBoard[j][i].team == 0 && _pBoard[j][i].type == 0) {
_pBoard[j][i] = empty;
}
}
}
// }
}
1. 현재 플레이보드의 상태 출력
2. 각 팀의 킹의 생존여부 확인하며 킹이 없을 경우 팀의 패배처리
Piece* ChessBoard::ChessDisplay(Piece _pBoard[][10], int _turn) {
// Sleep(100);
system("cls");
int King[2] = { 0, };
for (int y = 0; y <= 9; y++) {
// printf("42\n");
for (int x = 0; x <= 9; x++) {
// printf("43\n");
int team, type;
type = _pBoard[y][x].type;
team = _pBoard[y][x].team;
if (type >= 1) {
if (team == 0)
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 1);
else if (team == 1)
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
}
else {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
}
if (y == 0 || x == 0) {
printf("%d ", _MAX(y,x));
continue;
}
switch (type) {
case -1:
printf("ㅣ ");
break;
case 0:
printf(".. ");
break;
case 1:
printf("Pa ");
break;
case 2:
printf("Ro ");
break;
case 3:
printf("Kn ");
break;
case 4:
printf("Bi ");
break;
case 5:
printf("Qu ");
break;
case 6:
printf("Ki ");
King[team]=1;
break;
default:
printf(" ");
}
}
printf("\n");
}
printf("Press Q to Exit\n");
printf("Press R to Restart\n");
printf("\nturn: %d", _turn);
if (_turn % 2 == 1)
printf(" White\n");
else
printf(" Black\n");
if (King[0] == 0) {
system("cls");
printf("White Win!!\n");
Sleep(1000);
exit(0);
}
if (King[1] == 0) {
system("cls");
printf("Black Win!!\n");
Sleep(1000);
exit(0);
}
return *_pBoard;
}
1. Window.h, conio.h 의 _getch(), gotoXY() 를 이용해 키보드로 입력받음
2. 'R' 입력의 경우 재시작, 'Q' 입력의 경우 게임 종료
3. Moveto() 를 return 하여 이동 성공 여부를 반환
#include "Board.h"
#include<Windows.h>
#include<conio.h>
using namespace std;
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
#define ENTER 13
#define QUIT 81
#define quit 113
#define RESTART 82
#define restart 114
void gotoXY(int x, int y) {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);
}
int ChessBoard::GetCommand2(Piece _pBoard[][10], int* _turn) {
int ax=0, ay=0, bx=0, by=0;
int input = 0;
int x = 3;
int y = 1;
// if (input == 224)
// input = _getch();
if (*_turn % 2 == 0) {
x = 3;
y = 8;
}
while (input != ENTER) {
gotoXY(x, y);
input = _getch();
if (input == 224)
input = _getch();
switch (input) {
case UP:
if (y > 0)
y--;
break;
case DOWN:
if (y < 10)
y++;
break;
case RIGHT:
if (x < 10*3)
x+=3;
break;
case LEFT:
if (x > 0)
x-=3;
break;
case ENTER:
ax = x / 3;
ay = y;
break;
case RESTART: {
system("cls");
printf("RESTART\n");
*_turn = 1;
Sleep(1000);
system("cls");
ChessBoard RePlay = ChessBoard(_pBoard);
RePlay.ChessDisplay(_pBoard,1);
break;
}
case QUIT:
system("cls");
printf("...Quit The Game...\n");
Sleep(1000);
exit(0);
}
}
input = 0;
while (input != ENTER) {
gotoXY(x, y);
input = _getch();
if (input == 224)
input = _getch();
switch (input) {
case UP:
if (y > 0)
y--;
break;
case DOWN:
if (y < 10)
y++;
break;
case RIGHT:
if (x < 10 * 3)
x += 3;
break;
case LEFT:
if (x > 0)
x -= 3;
break;
case ENTER:
bx = x / 3;
by = y;
break;
case RESTART: {
printf("RESTART\n");
ChessBoard RePlay = ChessBoard(_pBoard);
break;
}
case QUIT:
system("cls");
printf("...Quit The Game...\n");
Sleep(1000);
exit(0);
}
}
return MoveTo(ax,ay,bx,by,_pBoard);
}
1. (ax,ay) 위치의 말이 ,(bx,by) 로 이동함을 의미
2. 6개의 말의 종류에 맞추어 6개의 함수 구현
3. 이동이 가능한 경우 _move() 함수로 (ax,ay) 를 비우고 (bx,by) 에 (ax,ay) 의 정보를 넣음
void _move(int ax, int ay, int bx, int by, Piece _pBoard[][10]) {
_pBoard[by][bx].type = _pBoard[ay][ax].type;
_pBoard[by][bx].team = _pBoard[ay][ax].team;
_pBoard[ay][ax].type = 0;
_pBoard[ay][ax].team = -1;
}
#include"Board.h"
#include<algorithm>
#include<math.h>
#include<conio.h>
#include<Windows.h>
using namespace std;
int Pa(int team, int ax, int ay, int bx, int by,Piece _pBoard[][10]);
int Ro(int team, int ax, int ay, int bx, int by, Piece _pBoard[][10]);
int Kn(int team, int ax, int ay, int bx, int by, Piece _pBoard[][10]);
int Bi(int team, int ax, int ay, int bx, int by, Piece _pBoard[][10]);
int Qu(int team, int ax, int ay, int bx, int by, Piece _pBoard[][10]);
int Ki(int team, int ax, int ay, int bx, int by, Piece _pBoard[][10]);
void gotoXY(int x, int y);
int ChessBoard::MoveTo(int ax, int ay, int bx, int by, Piece _pBoard[][10]) {
// Piece _pBoard[10][10] = ChessBoard::_pBoard;
int team = _pBoard[ay][ax].team;
int type =_pBoard[ay][ax].type;
int tmp_B[10][10] = { 0, }; //0 불가능 1 가능 2 어택
gotoXY(0, 13);
if (ax < 1 || ax>8 || bx < 1 || bx>8 || ay < 1 || ay>8 || by < 1 || by>8) {
printf("input error\n");
return 0;
}
switch (type) {
case -1:
printf("empty");
return 0;
break;
case 0:
printf("empty");
return 0;
break;
case 1:
return Pa(team, ax, ay, bx, by,_pBoard);
break;
case 2:
return Ro(team, ax, ay, bx, by, _pBoard);
break;
case 3:
return Kn(team, ax, ay, bx, by, _pBoard);
break;
case 4:
return Bi(team, ax, ay, bx, by, _pBoard);
break;
case 5:
return Qu(team, ax, ay, bx, by, _pBoard);
break;
case 6:
return Ki(team, ax, ay, bx, by, _pBoard);
break;
default:
return 0;
printf(" ");
}
return 0;
}
Pawn
int Pa(int team, int ax, int ay, int bx, int by, Piece _pBoard[][10]) {
if (team == 1) { // White
if (_pBoard[by][bx].type > 0) {
if (ay + 1 == by && abs(ax - bx) == 1) {
_move(ax, ay, bx, by, _pBoard);
printf("attack\n");
return 2;
}
}
else if(ay == 2){
if (ax == bx && (by - ay == 1 || (by - ay == 2 && _pBoard[ay + 1][by].type < 1))) {
_move(ax, ay, bx, by, _pBoard);
printf("move\n");
return 1;
}
}
else {
if ((ax == bx && by - ay == 1)) {
_move(ax, ay, bx, by, _pBoard);
printf("move\n");
return 1;
}
}
printf("impossible\n");
return 0;
}
else if(team == 0){ // Black
if (_pBoard[by][bx].type > 0) {
if (ay - 1 == by && abs(ax - bx) == 1) {
_move(ax, ay, bx, by, _pBoard);
printf("attack\n");
return 2;
}
}
else if (ay == 7) {
if (ax == bx && (by - ay == -1 || (by - ay == -2 && _pBoard[ay - 1][by].type < 1))) {
_move(ax, ay, bx, by,_pBoard);
printf("move\n");
return 1;
}
}
else {
if ((ax == bx && by - ay == -1)) {
_move(ax, ay, bx, by, _pBoard);
printf("move\n");
return 1;
}
}
printf("impossible\n");
return 0;
}
return 0;
} //complete
Bishop
int Bi(int team, int ax, int ay, int bx, int by, Piece _pBoard[][10]) {
if (abs(ax - bx) != abs(ay - by)) {
printf("impossible\n");
return 0;
}
int N = abs(ax - bx);
if (ax > bx && ay > by) { //7
for (int i = 1; i < N - 1; i++) {
if (_pBoard[ay - i][ax - i].type >= 1) {
printf("impossible\n");
return 0;
}
}
}
if (ax > bx && ay < by) { //1
for (int i = 1; i < N - 1; i++) {
if (_pBoard[ay + i][ax - i].type >= 1) {
printf("impossible\n");
return 0;
}
}
}
if (ax < bx && ay > by) { //9
for (int i = 1; i < N - 1; i++) {
if (_pBoard[ay - i][ax + i].type >= 1) {
printf("impossible\n");
return 0;
}
}
}
if (ax < bx && ay < by) { //3
for (int i = 1; i <= N - 1; i++) {
if (_pBoard[ay + i][ax + i].type >= 1) {
printf("impossible\n");
return 0;
}
}
}
if (_pBoard[by][bx].type <= 0) {
printf("move\n");
_move(ax, ay, bx, by, _pBoard);
return 1;
}
else if (_pBoard[by][bx].team == team) {
printf("same team impossible\n");
return 0;
}
else if (_pBoard[by][bx].team != team && _pBoard[by][bx].team != -1) {
printf("attack\n");
_move(ax, ay, bx, by, _pBoard);
return 2;
}
return 0;
}
1. 계승, 캐슬링, 양파상 등의 체스 특수 규칙
2. 흑팀 백팀 선택 여부
3. 스코어보드 혹은 타이머
..etc
딱히 대단한 알고리즘이나 자료구조를 이용하지 않아도 충분히 구현 가능했다. 다만 체스의 경우 반드시 2명이 있어야 플레이 가능해 실제로 플레이 해보거나 디버깅시 어려움이 있었다. 다음 프로젝트는 혼자서도 플레이 가능한 주제로 잡는것이 좋겠다.