본문 바로가기

C++ in Windows/Challenges

ICPC 대비 문제 7. 체크 확인(Check the Check)

>> 문제 7. 체크 확인(Check the Check)

 

PC/UVa ID:110107/10196, 인기도: B, 성공률: 보통, 레벨 1

 

>> 문제

체스판 설정을 읽어서 킹이 공격받고 있는지(체크 상태인지) 확인하는 일을 해야 한다. 상대방의 다음 수에 의해 킹이 죽을 수 있는 위치에 있으면 킹이 체크 상태가 된다.

 

흰 말은 대문자로, 검은 말은 소문자로 표시된다. 흰 편은 항상 판의 아래쪽에, 검은 편은 판의 위쪽에 자리잡는다.

 

체스를 잘 모르는 사람들을 위해 각 말의 이동 방법을 설명하자면 다음과 같다.

 

(Pawn, p 또는 P): 한 번에 한 칸씩 앞으로만 갈 수 있다. 하지만 대각선에 있는 상대 말을 잡을 수 있으며 이 문제에서 이 부분에 주의해야 한다.

나이트(Knight, n 또는 N): 아래에 나와있는 것처럼 L자 모양으로 움직일 수 있다. 다른 말을 뛰어넘을 수 있는 유일한 말이다.

비숍(Bishop, b 또는 B): 대각선 방향으로 어느 쪽으로든 이동 거리에 제한을 받지 않고 움직일 수 있다.

(Rook, r 또는 R): 수직 또는 수평 방향으로 이동 거리에 제한을 받지 않고 움직일 수 있다.

(Queen, q 또는 Q): 수직, 수평, 대각선 방향으로 어느 쪽으로든 이동 거리에 제한을 받지 않고 움직일 수 있다.

(King, k 또는 K): 수직, 수평, 대각선 방향으로 어느 쪽으로든 한 칸을 움직일 수 있다.

 

다음은 각 말이 움직이는 방향을 보여주며 “*는 그 말이 잡을 수 있는 상대방 말의 위치를 나타낸다.

 

........

........

........

........

...p....

..*.*...

........

........

...*....

...*....

...*....

...*....

***r****

...*....

...*....

...*....

비숍

.......*

*.....*.

.*...*..

..*.*...

...b....

..*.*...

.*...*..

*.....*.

...*...*

*..*..*.

.*.*.*..

..***...

***q****

..***...

.*.*.*..

*..*..*.

........

........

........

..***...

..*k*...

..***...

........

........

나이트

........

........

..*.*...

.*...*..

...n....

.*...*..

..*.*...

........

 

다른 말을 건널뛸 수 있는 것은 나이트밖에 없다는 것을 꼭 기억해두자. 폰의 움직임은 어느 편인가에 따라 다르다. 검은 폰이면 아래쪽 대각선 방향으로, 흰색 폰이면 위쪽 대각선 방향을 한칸만 움직일 수 있다. 위에 있는 예는 소문자 “p”로 표시된 검은 폰의 움직임을 나타낸 것이다. 방금 움직인다라고 표현한 것은 폰의 상대방 말을 잡을 수 있는 경우를의미한다.


>> 입력

입력에는 임의 개수의 체스판 배치가 들어있을 수 있으며 각 판은 각각 여덟 개 문자로 구성된 여덟 줄로 구성된다. “.”은 빈 칸을 의미하며 위에서 정의했듯이 각 말을 의미하는 대문자 또는 소문자가 입력된다. 틀린 문자는 없으며 두 킹이 모두 체크를 당하는 배치는 입력되지 않는다. “.”문자만으로 구성된 비어있는 체스판이 나올 떄까지 입력을 읽어야 하며 비어있는 체스판은 처리하지 않는다. 각 체스판 배치 사이에는 빈 줄이 하나씩 들어간다. 비어있는 판을 제외한 모든 판에는 정확하게 하나씩의 흰킹과 검은 킹이 들어있다.

 

>> 출력

입력된 각 판 배치에 대해 다음 중 한 가지 답을 출력한다.

Game #d: white king is in check.

Game #d: black king is in check.

Game #d: no king is in check.

여기에서 d 1에서 시작하는 게임 번호로 나타낸다.

 

>> 입력 예

..k.....

ppp.pppp

........

.R...B..

........

........

PPPPPPPP

K.......

 

rnbqkbnr

pppppppp

........

........

........

........

PPPPPPPP

RNBQKBNR

 

rnbqk.nr

ppp..ppp

....p...

...p....

.bPP....

........

PP..PPPP

RNBQKB.R

 

........

........

........

........

........

........

........

........

 

>> 출력예

Game #d: black king is in check.

Game #d: no king is in check.

Game #d: white king is in check.




main.cpp
#include <iostream>

#include "chessboard.h"


void main(void)
{
	chessboard cb;
	bool flag = true;	

	while(flag)
	{
		FILED_REF inBattleFiled;
		string str;

		// 체스의 현 배틀필드 입력.
		while(inBattleFiled.size() < MAX_HEIGHT)
		{
			getline(cin, str);

			if (str.size() == MAX_WIDTH)
				inBattleFiled.push_back(str);
		}

		int chessmanNum = cb.MakeChessBoard(inBattleFiled);
		if ( chessmanNum > 0 )
		{
			// 체크되는 왕을 찾고.
			cb.CheckKingFind();

			// 결과를 출력하고.
			cb.ResultPrint();
		
			// 보드를 날린다.
			cb.ReleaseBoard();
		}
		else
			flag = false;

	}	
}


chessboard.h
#ifndef _chessboard_
#define _chessboard_

#include <string>
#include "chessman.h"

#define FILED_REF	vector<string>		// 체스판을 만들기위한 참조데이터
#define FILED_LINE	vector<chessman*>	// 체스판의 한행
#define FILED_NOW	vector<FILED_LINE>	// 체스판


#define IDENTITY_NUM	12
static char ChessIdentity[IDENTITY_NUM] = { 
	     'p', 'n', 'b', 'r', 'q', 'k',
	     'P', 'N', 'B', 'R', 'Q', 'K' 
};

class chessboard{

private:
	FILED_REF	refFiled;	// 참조 필드
	FILED_NOW	nowFiled;	// 실제 필드

	bool isBoard;
	int ProgramCnt;

	int findKing;
public:
	chessboard(){
		this->isBoard = false;
		this->ProgramCnt = 0;
		this->findKing = 0;
	}

	~chessboard(){

	}

	int MakeChessBoard(const FILED_REF & pBF){
		// 보드가 이미 존재하면, 다시 작업을 하지 않는다.
		if ( this->isBoard == true ) return 0;
		this->isBoard = true;

		int ret = 0;

		this->refFiled = pBF;

		// 참조 필드의 유효성을 검사하고.
		ret = this->BeforCheck(this->refFiled);
		if ( ret > 0 )
		{	
			// 참조필드에 맞게 체스말을 세운다.
			this->StandChessMan(this->refFiled);
		}

		return ret;
	}
	
	void CheckKingFind(void)
	{
		FILED_NOW ::iterator filedLine;
		FILED_LINE	::iterator focus;
		
		int findFlag = 0; // 1 = white, -1 = black, 0 = not find

		for( filedLine = this->nowFiled.begin(); filedLine != this->nowFiled.end(); filedLine++)
		{
			for( focus = (*filedLine).begin(); focus != (*filedLine).end(); focus++)
			{
				// 방향을 우선 갖고 온다.
				VRANGE8 dir = (*focus)->GetRange();
				
				// 디버그 메시지.
				//cout << (*focus)->mColor << (*focus)->mPoint.x << (*focus)->mPoint.y << (*focus)->manName << endl;

				VRANGE8 ::iterator dirit;
				
				for( dirit = dir.begin(); dirit != dir.end(); dirit++ )
				{	
					VRANGE range = (*dirit);
					VRANGE ::iterator rangeit;

					POINT tPoint;
					for ( rangeit = range.begin(); rangeit != range.end(); rangeit++)
					{
						tPoint = (*rangeit);

						if ( this->nowFiled[tPoint.y][tPoint.x]->manName != '.' )
							break;
					}// range for

					// 디버그 메시지.
					//cout << this->nowFiled[tPoint.y][tPoint.x]->mPoint.x << this->nowFiled[tPoint.y][tPoint.x]->mPoint.y << this->nowFiled[tPoint.y][tPoint.x]->manName << endl;
					if ( this->nowFiled[tPoint.y][tPoint.x]->manName == 'k' 
						 && (*focus)->manName >= 'A' && (*focus)->manName <= 'Z')
						this->findKing = 1;
					else if ( this->nowFiled[tPoint.y][tPoint.x]->manName == 'K'
						 && (*focus)->manName >= 'a' && (*focus)->manName <= 'z')
						this->findKing = -1;

					if ( this->findKing != 0 ) break;
				}// dir for

				// 혹시모르니까 리턴 받은 벡터 삭제. 
				for( dirit = dir.begin(); dirit != dir.end(); dirit++ )
					(*dirit).erase((*dirit).begin(), (*dirit).end());
				dir.erase(dir.begin(), dir.end());

				if ( this->findKing != 0 ) break;
			}// filed line for
			if ( this->findKing != 0 ) break;
		}// filed for

	}
	
	void ResultPrint(void)
	{
		// 프로그램 카운터를 증가해 요구사항을 맞춤.
		++this->ProgramCnt;

		switch(this->findKing)
		{
			case 0:
				cout << "Game #" << this->ProgramCnt << ": no king is in check." << endl;
				break;
			case 1:
				cout << "Game #" << this->ProgramCnt << ": black king is in check." << endl;
				break;
			case -1:
				cout << "Game #" << this->ProgramCnt << ": white king is in check." << endl;
				break;
		}

	}

	void ReleaseBoard(void)
	{
		// 보드가 없는데 다시 해제 안하도록.
		if ( this->isBoard == false ) return;

		this->isBoard = false;
		this->findKing = 0;

		// 보드의 말들을 다 치운다.
		for( int y = 0; y < MAX_HEIGHT; y++) 
			for(int x = 0; x < MAX_WIDTH; x++) 
				delete this->nowFiled[y][x];
		
		// vector또한 삭제한다.
		FILED_NOW ::iterator filedit;
		for(filedit = this->nowFiled.begin(); filedit != this->nowFiled.end(); filedit++)
			(*filedit).erase((*filedit).begin(), (*filedit).end());
		this->nowFiled.erase(this->nowFiled.begin(), this->nowFiled.end());
		
		this->refFiled.erase(this->refFiled.begin(), this->refFiled.end());
	}

private:
	

	int BeforCheck(FILED_REF & pData) const {

		FILED_REF ::iterator it;
		int		ret = 0;

		// 입력된 참조필드(문자)중에 유효하지 않은 값이 들어있으면
		// 체스판을 만들지 않는다.

		for( it = pData.begin(); it != pData.end(); it++ ) 
		{
			for(unsigned int i = 0; i < (*it).size(); i++) 
			{
				bool check = false;
				for(int c = 0; c < IDENTITY_NUM; c++) 
				{
					if( (*it)[i] == ChessIdentity[c] ) 
					{
						check = true;
						break;
					}
				}
				
				if( check == true )
					++ret;
			}
		}
		
		return ret;
	}

	void StandChessMan(FILED_REF & pData) {
		
		for( int y = 0; y < MAX_HEIGHT; y++) 
		{
			FILED_LINE tFiled;

			for(int x = 0; x < MAX_WIDTH; x++) 
			{
				// 체스 말들을 하나씩 올려놓는다.
				this->StandChessMan(&tFiled, x, y, pData[y].c_str()[x]);				
			}
			
			// 한줄을 한번에 추가.
			this->nowFiled.push_back(tFiled);
		}
	}

	void StandChessMan(FILED_LINE * tFiled, const int & x, const int & y, const char & c )
	{	
		POINT pnt;
		pnt.x = x; pnt.y = y;
	
		// 디버그 메시지.
		//cout << "x : " << x << ", y : " << y << endl;

		// 체스말의 위치와 색갈 종류에 맞게 올려놓는다.
		switch( c )
		{
			case 'P':
				tFiled->push_back(new Pawn(CM::_WHITE_, pnt, c));
				break;
			case 'p':
				tFiled->push_back(new Pawn(CM::_BLACK_, pnt, c));
				break;
			case 'B':
				tFiled->push_back(new Bishop(CM::_WHITE_, pnt, c));
				break;
			case 'b':
				tFiled->push_back(new Bishop(CM::_BLACK_, pnt, c));
				break;
			case 'R':
				tFiled->push_back(new Rook(CM::_WHITE_, pnt, c));
				break;
			case 'r':
				tFiled->push_back(new Rook(CM::_BLACK_, pnt, c));
				break;
			case 'N':
				tFiled->push_back(new Knight(CM::_WHITE_, pnt, c));
				break;
			case 'n':
				tFiled->push_back(new Knight(CM::_BLACK_, pnt, c));
				break;
			case 'Q':
				tFiled->push_back(new Queen(CM::_WHITE_, pnt, c));
				break;
			case 'q':
				tFiled->push_back(new Queen(CM::_BLACK_, pnt, c));
				break;
			case 'K':
				tFiled->push_back(new King(CM::_WHITE_, pnt, c));
				break;
			case 'k':
				tFiled->push_back(new King(CM::_BLACK_, pnt, c));
				break;
			case '.':
				tFiled->push_back(new NullSpace(CM::_NULL_, pnt, c));
				break;

		}
	}
};

#endif


chessman.h
#pragma once

#ifndef _chessman_
#define _chessman_

#include <vector>

using namespace std;

#define MAX_WIDTH	8
#define MAX_HEIGHT	8

typedef struct tag_point{
	// 화면상의 좌표를 표현하는 구조체.
public:
	int x;
	int y;
	
	// POINT의 초기값은 -1, -1이다. 
	// 체스판 위에 존재하지 않는 좌표.
	tag_point()
	{
		x = -1;
		y = -1;
	}

	// 현포인트에서 이동할 좌표를 계산해서 반환.
	tag_point MovePoint(int pX, int pY) const{		
		tag_point t;

		t.x = x + pX;
		t.y = y + pY;

		return t;
	}

	// 움직일 좌표의 유효성 검사. 체스판 범위를 벗어나면 false
	bool CheckPoint(int pX, int pY) const{		
		return ((x+pX >= 0) && (x+pX < MAX_WIDTH) && (y+pY >= 0) && (y+pY < MAX_HEIGHT));
	}

	bool isZero(void) const {
		// 초기값이 -1, -1 이면
		return ((x == -1) && (y == -1));
	}

}POINT;

#define VRANGE	vector<POINT>	// 한방향의 가상 이동 거리
#define VRANGE8	vector<VRANGE>	// 8방향의 가상 이동거리


class VirtualRange{
	// 체스말이 현위치에서 움직일 방향의 포인터들을 찾아낸다. VRANGE로 반환
	// 다른 체스말에 의해 이동이 막히는 것은 보드에서 처리
	// 직선,대각선만 찾아내며, 나이트는 이 클래스를 사용할수 없다.
public:
	VirtualRange(){}
	~VirtualRange(){}


public:
	// 방향 정의.
	enum DIRECTION{
		D_TOP = 1, 
		D_TOP_RIGHT,
		D_RIGHT,
		D_BOT_RIGHT,
		D_BOT,
		D_BOT_LEFT,
		D_LEFT,
		D_TOP_LEFT
	};

// 코딩의 편의를 위한 매크로.
#define D_RIGHT_TOP D_TOP_RIGHT
#define D_RIGHT_BOT D_BOT_RIGHT
#define D_LEFT_TOP	D_TOP_LEFT
#define D_LEFT_BOT	D_BOT_LEFT

	enum RANGE{
		R_ONE = 1,
		R_FULL
	};

	// 외부에서는 이것만 호출하여 좌표를 찾아온다.
	void GetRange(VRANGE8 * retRange, const POINT & origin, const DIRECTION & dir, const RANGE & r) const {
		VRANGE range;

		range = this->Get(origin, dir, r);

		if ( range.size() > 0 )
			retRange->push_back(range);
	
	}

private:
	// 동작 분리자.
	VRANGE Get(const POINT & origin, const DIRECTION & dir, const RANGE & r) const {
		VRANGE retRange;
		
		if ( r == VirtualRange::R_ONE )
		{
			POINT ret = this->GetOne(origin, dir);

			if ( !ret.isZero() )
				retRange.push_back(ret);
		}
		else if ( r == VirtualRange::R_FULL )
		{
			this->GetMore(&retRange, origin, dir);
		}

		return retRange;
	}


	// 한칸씩 움직이는거 좌표찾기.
	POINT GetOne(POINT origin, DIRECTION dir) const {
		POINT ret;
		switch(dir)
		{
			case D_TOP:
				if (origin.CheckPoint(0, -1))
					ret = origin.MovePoint(0, -1);	
				break;
			case D_TOP_RIGHT:
				if (origin.CheckPoint(1, -1))
					ret = origin.MovePoint(1, -1);
				break;
			case D_RIGHT:
				if (origin.CheckPoint(1, 0))
					ret = origin.MovePoint(1, 0);
				break;
			case D_BOT_RIGHT:
				if (origin.CheckPoint(1, 1))
					ret = origin.MovePoint(1, 1);
				break;
			case D_BOT:
				if (origin.CheckPoint(0, 1))
					ret = origin.MovePoint(0, 1);
				break;
			case D_BOT_LEFT:
				if (origin.CheckPoint(-1, 1))
					ret = origin.MovePoint(-1, 1);
				break;
			case D_LEFT:
				if (origin.CheckPoint(-1, 0))
					ret = origin.MovePoint(-1, 0);
				break;
			case D_TOP_LEFT:
				if (origin.CheckPoint(-1, -1))
					ret = origin.MovePoint(-1, -1);
				break;
		}

		return ret;
	}

	// 멀리가는 것들 좌표 찾기. 재귀호출.
	void GetMore(VRANGE* retRange, POINT origin, DIRECTION dir) const {
		POINT ret;
		switch(dir)
		{
			case D_TOP:
				if (origin.CheckPoint(0, -1))
					ret = origin.MovePoint(0, -1);	
				break;
			case D_TOP_RIGHT:
				if (origin.CheckPoint(1, -1))
					ret = origin.MovePoint(1, -1);
				break;
			case D_RIGHT:
				if (origin.CheckPoint(1, 0))
					ret = origin.MovePoint(1, 0);
				break;
			case D_BOT_RIGHT:
				if (origin.CheckPoint(1, 1))
					ret = origin.MovePoint(1, 1);
				break;
			case D_BOT:
				if (origin.CheckPoint(0, 1))
					ret = origin.MovePoint(0, 1);
				break;
			case D_BOT_LEFT:
				if (origin.CheckPoint(-1, 1))
					ret = origin.MovePoint(-1, 1);
				break;
			case D_LEFT:
				if (origin.CheckPoint(-1, 0))
					ret = origin.MovePoint(-1, 0);
				break;
			case D_TOP_LEFT:
				if (origin.CheckPoint(-1, -1))
					ret = origin.MovePoint(-1, -1);
				break;
		}

		if ( !ret.isZero() )
		{
			retRange->push_back(ret);
			this->GetMore(retRange, ret, dir);
			
		}
	}


};

// VritualRange를 줄여쓰기 위해 VR로 매크로 선언
#define VR VirtualRange

class chessman{
	// 단순한 움직일 위치만 찾는다.
public:
	enum MAN_COLOR{
		_BLACK_ = 1,
		_WHITE_,
		_NULL_
	};

	chessman(void){}	
	chessman(const chessman::MAN_COLOR & color, const POINT & point, const char & Name)
	{
		this->mColor = color;
		this->mPoint = point;
		this->manName = Name;
	}
	~chessman(void){}


public:
	MAN_COLOR	mColor;
	POINT		mPoint;
	char		manName;

	virtual VRANGE8 GetRange(void) const = 0;

};

#define CM chessman

class Pawn:public chessman{
	// 폰은 전방 대각선 한칸만 알면 된다.
	// 흑백에 따라 전방은 반전된다.
public:
	Pawn(){}
	~Pawn(){}
	
	Pawn(const CM::MAN_COLOR & color, const POINT & point, const char & Name )
	{
		this->mColor = color;
		this->mPoint = point;
		this->manName = Name;
	}
	

	virtual VRANGE8 GetRange(void) const{	
		VRANGE8 retRange;

		if (this->mColor == chessman::_BLACK_)
		{
			VR().GetRange(&retRange, this->mPoint, VR::D_LEFT_BOT,	VR::R_ONE);
			VR().GetRange(&retRange, this->mPoint, VR::D_RIGHT_BOT, VR::R_ONE);		
		}
		else if (this->mColor == chessman::_WHITE_)
		{
			VR().GetRange(&retRange, this->mPoint, VR::D_LEFT_TOP,	VR::R_ONE);
			VR().GetRange(&retRange, this->mPoint, VR::D_RIGHT_TOP, VR::R_ONE);			
		}

		return retRange;
	}
};


class Rook: public chessman{
public:
	Rook(){}
	~Rook(){}
	Rook(const CM::MAN_COLOR & color, const POINT & point, const char & Name)
	{
		this->mColor = color;
		this->mPoint = point;
		this->manName = Name;
	}

	// 룩은 흑백 상관 없이 4방향 직선만 알면 된다.
	virtual VRANGE8 GetRange(void) const{
		VRANGE8 retRange;
		
		VR().GetRange(&retRange, this->mPoint, VR::D_TOP,	VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_RIGHT, VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_LEFT,	VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_BOT,	VR::R_FULL);
	
		return retRange;

	}
};

class Bishop: public chessman{
public:
	Bishop(){}
	~Bishop(){}
	Bishop(const CM::MAN_COLOR & color, const POINT & point, const char & Name)
	{
		this->mColor = color;
		this->mPoint = point;
		this->manName = Name;
	}

	// 폰은 흑백 상관 없이 대각선 방향의 직선만 알면된다.
	virtual VRANGE8 GetRange(void) const {
		VRANGE8 retRange;
		
		VR().GetRange(&retRange, this->mPoint, VR::D_BOT_LEFT,	VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_BOT_RIGHT, VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_TOP_LEFT,	VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_TOP_RIGHT,	VR::R_FULL);
	
		return retRange;
	}
};

class Queen: public chessman{
public:
	Queen(){}
	~Queen(){}
	Queen(const CM::MAN_COLOR & color, const POINT & point, const char & Name)
	{
		this->mColor = color;
		this->mPoint = point;
		this->manName = Name;
	}

	// 퀸은 비숍과 룩을 합친것과 같다.
	virtual VRANGE8 GetRange(void) const {
		VRANGE8 retRange;
		
		VR().GetRange(&retRange, this->mPoint, VR::D_TOP,		VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_RIGHT,		VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_LEFT,		VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_BOT,		VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_BOT_LEFT,	VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_BOT_RIGHT, VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_TOP_LEFT,	VR::R_FULL);
		VR().GetRange(&retRange, this->mPoint, VR::D_TOP_RIGHT,	VR::R_FULL);
	
		return retRange;
	}
};

class King: public chessman{
public:
	King(){}
	~King(){}
	King(const CM::MAN_COLOR & color, const POINT & point, const char & Name)
	{
		this->mColor = color;
		this->mPoint = point;
		this->manName = Name;
	}
	// 킹은 퀸과 비슷하지만 한칸씩 움직인다.
	virtual VRANGE8 GetRange(void) const {
		VRANGE8 retRange;
		
		VR().GetRange(&retRange, this->mPoint, VR::D_TOP,		VR::R_ONE);
		VR().GetRange(&retRange, this->mPoint, VR::D_RIGHT,		VR::R_ONE);
		VR().GetRange(&retRange, this->mPoint, VR::D_LEFT,		VR::R_ONE);
		VR().GetRange(&retRange, this->mPoint, VR::D_BOT,		VR::R_ONE);
		VR().GetRange(&retRange, this->mPoint, VR::D_BOT_LEFT,	VR::R_ONE);
		VR().GetRange(&retRange, this->mPoint, VR::D_BOT_RIGHT, VR::R_ONE);
		VR().GetRange(&retRange, this->mPoint, VR::D_TOP_LEFT,	VR::R_ONE);
		VR().GetRange(&retRange, this->mPoint, VR::D_TOP_RIGHT,	VR::R_ONE);
	
		return retRange;
	}
};

class Knight: public chessman{
public:
	Knight(){}
	~Knight(){}
	Knight(const CM::MAN_COLOR & color, const POINT & point, const char & Name)
	{
		this->mColor = color;
		this->mPoint = point;
		this->manName = Name;
	}
	// 나이트는 8방향 ㄴ자로 움직인다. 나이트는 특별하다.
	virtual VRANGE8 GetRange(void) const {
		VRANGE8 retRange;
		
		this->GetVRange(&retRange, -2, -1);
		this->GetVRange(&retRange, -2,  1);
		
		this->GetVRange(&retRange,  2, -1);
		this->GetVRange(&retRange,  2,  1);

		this->GetVRange(&retRange, -1,  2);
		this->GetVRange(&retRange,  1,  2);

		this->GetVRange(&retRange, -1, -2);
		this->GetVRange(&retRange,  1, -2);

		return retRange;
	}

private:
	void GetVRange(VRANGE8* retRange, int x, int y) const {
		VRANGE range;
		POINT point;

		if (this->mPoint.CheckPoint(x, y))
		{
			point = this->mPoint.MovePoint(x, y);	

			if ( !point.isZero() )
			{
				range.push_back(point);
				retRange->push_back(range);
			}
		}
	}
};

class NullSpace: public chessman{
public:
	NullSpace(){}
	~NullSpace(){}
	NullSpace(const CM::MAN_COLOR & color, const POINT & point, const char & Name)
	{
		this->mColor = color;
		this->mPoint = point;
		this->manName = Name;
	}
	// 체스말이 없는곳.
	virtual VRANGE8 GetRange(void) const {
		VRANGE8 retRange;

		return retRange;
	}
};
#endif




내가 지금까지 코딩하던 스타일과는 조금 다르게 코딩했다.

const를 쓰거나, vector를 쓰거나. 얼마 달라진건 없지만, 그래도 조금씩 바꿔나가는중.


코딩 순서는 chessman.h -> main.cpp -> chessboard.h


클래스를 만들다 보니 소스가 길어졌고.


마무리 하는 부분에서 귀찮아서 대충해버린 부분도 있다. (ResultPrint, CheckKingFind 부분)


나중에 CheckKingFind 부분을 조금 변형하고, 인터페이스를 만들면.

체스 게임을 만들수 있을꺼 같다. 말이 이동할땐 swap을 이용해서 NullSpace랑 교체하고,

상대방 말을 공격할땐 swap한뒤 상대방 말을 NullSpace로 변경해주면 될 듯하다.


또 킹과 룩이 움직이지 않았을때 아무런 장해물이 없으면, 자리를 재 배치하는건 특별하게 예외처리를 해주면 될듯하니.


뭐, 나중에 시간이 많이 남을때 만드는걸 고려해보자.


struct에 함수를 만드니까 편하다는 것을 느낌.

vector의 난잡한 사용이 해제할때 문제가 된다는것도 알게 됬다. 코드에서 보기에도 아름답지가 않음.


다 만들고 나니 체스말 하나씩 올리는 부분에서 예외가 발생될꺼 같다.


다음부터는 try .. catch 를 생활화 해야겠다.