C++
[C++] Solitaire 카드 게임 프로그래밍
i.m_ujin
2016. 5. 15. 01:20
Stack을 이용한 자료구조 과제.
Solitaire 게임이라면...아주 전형적인 Stack 사용 예제 아닌가??
하면서도 되게 흥미로웠던 기억이 있어서 약간 정리 안된 코드지만
올려봐야지
#include<iostream>
#include<vector>
#include<string>
#include<cstdlib>
#include<time.h>
#include<iomanip>
using namespace std;
template<class T>
class Stack
{
public:
Stack(int stackCapacity = 10);
// 처음에 크기가 stackCapacity인 공백 스택을 생성
bool IsEmpty() const;
// 스택의 원소 수가 0이면 true, 아니면 false를 반환
T& Top() const;
// 스택의 상위 원소를 반환
void Push(const T& item);
// 스택의 상위에 item을 삽입
void Pop();
// 스택의 상위 원소를 삭제
int get_topindex(){return top;}
private:
T *stack; // 스택 원소를 위한 배열
int top; // 톱 원소의 위치
int capacity; // 스택 배열의 크기
void ChangeSize1D(T*& a, const int oldSize, const int newSize);
};
template<class T>
Stack<T>::Stack(int stackCapacity) : capacity(stackCapacity), top(-1)
{
if(capacity < 1)
throw "Stack capacity must be>0";
stack = new T[capacity];
}
template<class T>
inline bool Stack<T>::IsEmpty() const
{
return (top == -1);
}
template<class T>
inline T& Stack<T>::Top() const
{
if(IsEmpty())
throw "Stack is empty";
return stack[top];
}
template<class T>
void Stack<T>::Push(const T& item)
{
if(top == capacity-1)
{
ChangeSize1D(stack, capacity, 2*capacity);
capacity *= 2;
}
stack[++top] = item;
}
template<class T>
void Stack<T>::Pop()
{
if(IsEmpty())
throw "Stack is empty. Cannot delete";
top--;
}
template<class T>
void Stack<T>::ChangeSize1D(T*& a, const int oldSize, const int newSize)
{
if(newSize<0)
throw "New length must be >= 0";
T* temp = new T[newSize]; // 새로운 배열
int number = min(oldSize, newSize); // 복사할 원소 수
copy(a, a+number, temp);
delete []a; // 이전 메모리 제거
a = temp;
}
struct Card{
char type;
string num;
};
class Solitaire{
public:
Solitaire(){
}
void card_init();
void print_pile();
void playing_game();
private:
Stack<Card>playing[7];
Stack<Card>stock;
Stack<Card>waste;
Stack<Card>spade, diamond, heart, clover;
static string cardnum[13];
};
string Solitaire::cardnum[13]={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
void Solitaire ::card_init(){
vector<Card>temp_card;
srand((unsigned)time(NULL));
char temptype[4]={'S', 'H', 'D', 'C'};
for(int i=0;i<4;i++){
for(int j=0;j<13;j++){
Card temp;
temp.type=temptype[i];
temp.num =cardnum[j];
temp_card.push_back(temp);
}
}
for(int i=0;i<52;i++){
int first = rand()%52;
int second = rand()%52;
Card swap;
swap=temp_card[first];
temp_card[first] = temp_card[second];
temp_card[second]=swap;
}
for(int i=0;i<52;i++){
if(i<1){
playing[0].Push(temp_card[i]);
}
else if(i<3){
playing[1].Push(temp_card[i]);
}
else if(i<6){
playing[2].Push(temp_card[i]);
}
else if(i<10){
playing[3].Push(temp_card[i]);
}
else if(i<15){
playing[4].Push(temp_card[i]);
}
else if(i<21){
playing[5].Push(temp_card[i]);
}
else if(i<28){
playing[6].Push(temp_card[i]);
}
else{
stock.Push(temp_card[i]);
}
}
print_pile();
}
void Solitaire::print_pile(){
if(waste.get_topindex()!=-1){
cout<<"waste pile="<<waste.Top().type<<"."<<waste.Top().num<<endl;
}
else {
cout<<"waste pile="<<endl;
}
for(int i=0;i<7;i++){
for(int j=0;j<playing[i].get_topindex();j++){
cout<<setw(5)<<"X";
}
cout<<" "<<playing[i].Top().type<<"."<<playing[i].Top().num<<endl;
}
if(spade.get_topindex()!=-1){
cout<<"Spade "<<spade.Top().type<<"."<<spade.Top().num<<endl;
}
else{
cout<<"Spade "<<endl;
}
if(heart.get_topindex()!=-1){
cout<<"Heart "<<heart.Top().type<<"."<<heart.Top().num<<endl;
}
else{
cout<<"Heart "<<endl;
}
if(diamond.get_topindex()!=-1){
cout<<"Diamond "<<diamond.Top().type<<"."<<diamond.Top().num<<endl;
}
else{
cout<<"Diamond "<<endl;
}
if(clover.get_topindex()!=-1){
cout<<"Clover "<<clover.Top().type<<"."<<clover.Top().num<<endl;
}
else{
cout<<"Clover "<<endl;
}
}
void Solitaire::playing_game(){
bool flag = true;
int num=0;
bool do_some = true;
while(num++<10){
if(do_some){
waste.Push(stock.Top());
stock.Pop();
}
if(waste.IsEmpty()) {
waste.Push(stock.Top());
stock.Pop();
}
if(waste.Top().type=='S' && waste.Top().num==cardnum[spade.get_topindex()+1]){
print_pile();
spade.Push(waste.Top());
waste.Pop();
do_some=false;
}
else if(waste.Top().type=='H' && waste.Top().num==cardnum[heart.get_topindex()+1]){
print_pile();
heart.Push(waste.Top());
waste.Pop();
do_some=false;
}
else if(waste.Top().type=='D' && waste.Top().num==cardnum[diamond.get_topindex()+1]){
print_pile();
diamond.Push(waste.Top());
waste.Pop();
do_some=false;
}
else if(waste.Top().type=='C' && waste.Top().num==cardnum[clover.get_topindex()+1]){
print_pile();
clover.Push(waste.Top());
waste.Pop();
do_some=false;
}
for(int i=0;i<7;i++){
char temptype = playing[i].Top().type;
if(playing[i].get_topindex()!=-1){
switch(temptype){
case 'S':
{
if(playing[i].Top().num==cardnum[spade.get_topindex()+1]){
print_pile();
spade.Push(playing[i].Top());
playing[i].Pop();
do_some=false;
}
else{
do_some=true;
}
break;
}
case 'H':
{
if(playing[i].Top().num==cardnum[heart.get_topindex()+1]){
print_pile();
heart.Push(playing[i].Top());
playing[i].Pop();
do_some=false;
}
else{
do_some=true;
}
break;
}
case 'D':
{
if(playing[i].Top().num==cardnum[diamond.get_topindex()+1]){
print_pile();
diamond.Push(playing[i].Top());
playing[i].Pop();
do_some=false;
}
else{
do_some=true;
}
break;
}
case 'C':
{
if(playing[i].Top().num==cardnum[clover.get_topindex()+1]){
print_pile();
clover.Push(playing[i].Top());
playing[i].Pop();
do_some=false;
}
else{
do_some=true;
}
break;
}
}
}
}
print_pile();
}
}
int main(){
Solitaire solitaire;
solitaire.card_init();
solitaire.playing_game();
return 0;
}
약간 가독성이 떨어지긴 하지만, S, D, H, C는 Spade, Diamond, Heart, Clover를 나타낸다.
카드는 무늬마다 13장씩 총 52장이 있고 이 문제의 요구사항은 자동 Solitaire 프로그램을 만드는 것이었다.
Solitaire는 카드를 잘못놓기 시작하면 끝이 나지 않기 때문에 무한 loop를 돌고싶지 않아서 10번 정도만 loop를 돌도록 했다.
뭐...저건 숫자만 수정하면 고쳐질거니까 한 100번까진 돌려봤는데
별 다른 알고리즘 없이 맨 처음 나오는 카드를 바로 더미에 올려주는 거라 100번 돈다 해서 게임이 끝날 가능성은 거의 희박하다....ㅎㅎㅋㅋㅋㅋㅋ
결과화면도 약간 가독성이 떨어지는거 같기도 하네....하하
어쨌든 이와 같이 동작 가능하다. 헐 그리고 캡쳐엔 안나왔지만 playing 더미에 있는 카드들끼리도 겹치기 가능하다.
만약 코드를 손본다면
1. 자동으로 10턴 이런것 보다는 사용자 입력이 더 재밌을거 같다.
2. 결과 가독성 면에서도 떨어지는것 같아서 출력부분을 이쁘게 수정...하고싶다
3. 이왕 효율적이게 하려면 직접 구현한 stack보다는 STL이 낫겠지....