'야구 게임'이라하면 '당연히' 진짜 야구를 말하는 것이 아니라,
숫자를 맞추는 게임이란 건 아실 겁니다. ^^;
룰은 워낙 간단하고 유명해서 설명이 불필요하겠죠?
가장 간단하게 구현할 수 있는 게임으로 유명하고,
(공학용 계산기에 이 게임을 프로그램해서 넣었던 기억이 나네요. *^^*)
소스도 찾아보면 무지하게 많지만,
이번에 올리는 소스는 STL을 사용한 겁니다.
스스로 만든 건 아니고요,
Herb Sutter의 'More Exceptional C++'의 Item 11: Mastermind 에 있는 소스를
야구 게임으로 수정했습니다.
(원래 미국에도 이와 비슷한 게임으로 Mastermind라는 게 있습니다.
숫자대신 문자를 쓰고, 중복을 허용하는 게 차이점이죠.)
그리 길지 않은 소스이므로, 본문에 전부 붙여 넣습니다.
Generic Programming의 예술이라고 할 정도로 멋진 소스코드입니다.
전형적인 STL 코드답게, for나 while과 같은 루프는 전혀 없지요.
중복을 방지하는 방법으로 SGI STL(STLport)의 random_sample 알고리듬을 사용했습니다.
그러므로 컴파일러가 g++이나 C++빌더 6가 아닌 경우는 STLport를 별도로 설치해야 합니다.
//---------------------------------------------------------------------------
#ifndef __BORLANDC__
#include <ctime>
#endif
#include <cstdlib>
#include <string>
#include <iostream>
#pragma hdrstop
#include <iterator>
#include <algorithm>
#include <numeric>
#include <functional>
//---------------------------------------------------------------------------
using namespace std;
class Combination
{
public:
Combination(int length, bool rep) : comb_(length, '.'), num_round(0)
{
if (rep) // 중복 허용
generate(comb_.begin(), comb_.end(), ChooseChar(&chars));
else // 중복 금지
random_sample(chars.begin(), chars.end(),
comb_.begin(), comb_.end());
#ifdef _DEBUG
cout << comb_ << endl; // 디버그 모드에서는 컴퓨터가 생각(?)한 값이 표시됩니다.
#endif
Prompt();
}
bool operator()(string& guess) // one round
{
size_t cok, pok; // right char(color or number) & place(position)
guess.resize(comb_.size(), ' ');
cok = accumulate(chars.begin(), chars.end(),
CMatch(0, &comb_, &guess), CMatch::Count);
pok = inner_product(comb_.begin(), comb_.end(), guess.begin(), 0,
plus<int>(), equal_to<char>());
cout << pok_text << pok << cok_text << cok;
bool solved = (pok == comb_.size());
if (solved)
cout << " - solved!\n";
else
Prompt();
return solved;
}
private:
void Prompt() { cout << "\n\nguess " << ++num_round << " --> "; }
string comb_; // actual combination;
static const string chars, cok_text, pok_text; // possible chars;
int num_round;
class CMatch {
public:
CMatch(int i, const string* s1, const string* s2)
: cok_(i), s1_(s1), s2_(s2) {}
operator int() const { return cok_; }
static CMatch Count(CMatch& cm, char c)
{
return CMatch(
cm.cok_ + min(count(cm.s1_->begin(), cm.s1_->end(), c),
count(cm.s2_->begin(), cm.s2_->end(), c)),
cm.s1_, cm.s2_);
}
private:
int cok_;
const string *s1_, *s2_;
};
class ChooseChar {
public:
ChooseChar(const string* cs) : cs_(cs) {};
char operator()() {
#ifdef __BORLANDC__
return (*cs_)[random(cs_->size())];
#else
return (*cs_)[rand() % cs_->size())];
#endif
}
private:
const string *cs_;
};
};
const string Combination::chars = "0123456789",
Combination::cok_text = " ball:",
Combination::pok_text = "strike:";
int main()
{
#ifdef __BORLANDC__
randomize();
#else
srand(time(0));
#endif
find_if(istream_iterator<string>(cin), istream_iterator<string>(),
Combination(4, false)); // 한국식 야구의 기본 설정: 4자리수, 중복 금지
return 0;
}
//---------------------------------------------------------------------------
|