Game Programming

깊이있는 삽질 Ubuntu Korea Community Wiki
이동: 둘러보기, 검색

C++을 이용한 게임 만들기[편집]

  • C++로 게임 제작의 기본기를 쌓는것이 목적
  • Beginnning C++ Through Game Programming의 내용을 간략화했다.

왜 C++인가[편집]

  • C++은 빠른편이고, 고급언어인 편에 속한다.
  • 사실상 업계 표준임.
  • C에 비해 Object Oriented 프로그래밍이 쉽다.

Game Over[편집]

  • C++로 Game Over를 짜보자Hello world랑 뭐가 다른건데!!
// Game Over
// A first C++ program

#include <iostream>

int main()
{
    std::cout << "Game Over!" << std::endl;
    return 0;
}
  • Game Over 2.0을 짜보자조또 바뀐것 없다.
  • 네임스페이스를 써서
// Game Over 2.0
// Demonstrates a using directive

#include <iostream>
using namespace std;

int main()
{
    cout << "Game Over!" << endl;
    return 0;
}
  • Game Over 3.0이다.반복학습 쩐다
// Game Over 3.0
// Demonstrates using declarations

#include <iostream>
using std::cout;
using std::endl;

int main()
{
    cout << "Game Over!" << endl;
    return 0;
}

비싼 계산기[편집]

  • 연산자를 이해하기 위해 비싼 계산기를 짜보자.
// Expensive Calculator
// Demonstrates built-in arithmetic operators

#include <iostream>
using namespace std;

int main()
{
    cout << "7 + 3 = " << 7 + 3 << endl;
    cout << "7 - 3 = " << 7 - 3 << endl;
    cout << "7 * 3 = " << 7 * 3 << endl;

    cout << "7 / 3 = " << 7 / 3 << endl;
    cout << "7.0 / 3.0 = " << 7.0 / 3.0 << endl;

    cout << "7 % 3 = " << 7 % 3 << endl;
    cout << "7 + 3 * 5 = " << 7 + 3 * 5 << endl;
    cout << "(7 + 3) * 5 = " << (7 + 3) * 5 << endl;

    return 0;
}

게임 스탯[편집]

  • 비행 슈팅게임에서 상태출력에 대해 생각하려 한다.
// Game Stats
// Demonstrates declaring and initializing variables

#include <iostream>
using namespace std;

int main()
{
    int score;
    double distance;
    char playAgain;
    bool shieldsUp;

    short lives, aliensKilled;

    score = 0;
    distance = 1200.76;
    playAgain = 'y';
    shieldsUp = true;
    lives = 3;
    aliensKilled = 10;
    double engineTemp = 6572.89;

    cout << "\nscore: " << score << endl;
    cout << "distance: " << distance << endl;
    cout << "playAgain: " << playAgin << endl;
    // Bool 표현은 애매하므로 shieldup은 생략한다.
    cout << "lives: " << lives << endl;
    cout << "aliensKilled: " << aliensKilled << endl;
    cout << "engineTemp: " << engineTemp << endl;

    int fuel;
    cout << "\nHow much fuel? ":
    cin >> fuel;
    cout << "fuel: " << fuel << endl;

    typedef unsigned short int ushort;
    ushort bonus = 10;
    cout << "\nbonus: " << bonus << endl;

    return 0;
}
  • 어디서 많이 보던 것들이지?겜 좀 해봐야 겜을 만들징
  • 이제 좀 계산하는 방법에 대해 알아보자.
/* game_stats2.cc */
// Game Stats 2.0
// Demonstrates arithmetic operations with variables

#include <iostream>
using namespace std;

int main()
{
    unsigned int score = 5000;
    cout << "score: " << score << endl;

    // 값을 살짝 바꾼다.
    score = score + 100;
    cout << "score: " << score << endl;

    // 값 증가의 다른 버전
    score += 100;
    cout << "score: " << score << endl;

    // 값 증가의 또다른 버전
    int lives = 3;
    ++ lives;
    cout << "lives: " << lives << endl;

    lives = 3;
    lives++;
    cout << "lives: " << lives << endl;

    lives = 3;
    int bonus = ++lives * 10;
    cout << "lives, bonus = " << lives << ", " << bonus << endl;

    lives = 3;
    bonus = lives++ * 10;
    cout << "lives, bonus = " << lives << ", " << bonus << endl;

    // 정수 최대값은 결국?
    score = 4294967295;
    cout << "\nscore: " << score << endl;
    ++score;
    cout << "score: " << score << endl;

    return 0;
}
  • 자. 이제 3.0이다뭔 이따위것까지 3.0이여
/* game_stats3.cc */
// Game Stats 3.0
// Demonstrates constants

#include <iostream>
using namespace std;

int main()
{
    const int ALIEN_POINTS = 150;
    int aliensKilled = 10;
    int score = aliensKilled * ALIEN_POINTS;
    cout << "score: " << score << endl;

    enum difficulty (NOVICE, EASY, NORMAL, HARD, UNBEATABLE);
    difficulty myDifficulty = EASY;

    enum ship (FIGHTER = 25, BOMBER, CRUISER = 50, DESTROYER = 100);
    ship myShip = BOMBER;
    cout << "\nTo upgrade my ship to Cruiser will cost " << (CRUISER - myShip) << " Resource Points.\n";
    return 0;
}
  • 상수의 사용법이다.
  • 안바뀌는건 const 지정을 해놓으면 나중에 편하다.
  • 열거형 변수. 짜증나게 값 입력을 안해놨으니 이해가 힘들거임.좀 복붙이라도 하던지.
  • 한번 돌려보면 어느정도 감이 잡히는거고, 내용을 설명하기엔 좀..이럴때 책이 필요한거임. 다른 언어 해본사람은 금방 눈에 들어올거고.

Lost Fortune[편집]

  • 기본을 어느정도 했으면 진짜 간단한거 하나 해보자.
/* lost_fortune.cc */
// Lost Fortune
// A personalized adventure

#include <iostream>
#include <string>

using std::cout;
using std::cin;
using std::endl;
using std::string;

/* string을 포함했다. 이건 표준 라이브러리의 일종인데, 문자열 처리를 위한 라이브러리다. */

/* 사용자 정보를 입력받자. */
int main()
{
    const int GOLD_PIECES = 900;
    int adventurers, killed, survivors;
    string leader;

    // 플레이어 정보를 입력받는다.
    cout << "Welcome to Lost Fortune\n\n";
    cout << "Please enter the following for your personalized adventure\n";

    cout << "Enter a number: ";
    cin >> adventurers;

    cout << "Enter a number, samller than the first: ";
    cin >> killed;

    survivors = adventurers - killed;

    cout << "Enter your last name: ";
    cin >> leader;

    /* GOLD_PIECES는 모험가들이 찾는 행운의 금 조각이다. adventurers는 모험가의 숫자, killed는 모험하다 뒈진 사람의 숫자다. 여기서는 당신이 생존자 리더다. */

    // 스토리텔링
    cout << "\n A brave group of " << adventurers << " set out on a quest ";
    cout << "-- in search of the lost treasure of the Ancient Dwarves. ";
    cout << "The group was led by that legendary rogue. " << leader << ".\n";
    cout << "\n Along the way. a band of marauding ogres ambushed the aprty. ";
    cout << "All fought bravely under the command of " << leader;
    cout << ", and the ogres were defeated, but at a cost. ";
    cout << "Of the adventurers. " << killed << " were vanquished. ";
    cout << "leaving just " << survivors << " in the group.\n";
    cout << "\nThe party was about to give up all hope. ";
    cout << "But while laying the deceased to rest. ";
    cout << "they stumbled upon the buried fortune. ";
    cout << "So the adventurers split " << GOLD_PIECES << " gold pieces.";
    cout << leader << " held on to the extra " <<  (GOLD_PIECES % survivors);
    cout << " pieces to keep things fair of course.\n";

    return 0;
}
  • 별 게임도 아닌것 같은데.. 스토리텔링하고 끝나네..뭐 첨엔 다 그런거야

Score Rater[편집]

  • 점수 매기기, 조건문에 대한 이해를 해보자.
/* score_rater.cc */
// Score Rater
// Demonstrates the if statement

#include <iostream>

using namespace std;

int main()
{
    if(true)
        cout << "This is always displayed.\n\n";
    if(false)
        cout << "This is never displayed.\n\n";
    int score = 1000;
    if(score)
        cout << "Okay, at least you didn't score zero.\n\n";
    if(score > 500)
        cout << "You scored over 500. Nice.\n\n";
    if(score == 1000)
    {
        cout << "You scored a perfect 1000!\n";
        cout << "Now that's impressive.\n";
    }
    if(score > 500)
    {
        cout << "You scored at least 500.\n";
        if(score >= 1000)
            cout << "You scored 1000 or more!\n";
    }
    return 0;
}
  • 점수매기기 2.0. 이번엔 입력을 받아보자구.
/* score_rater2.cc */
// Score Rater 2.0
// Demonstrates the else caluse

#include <iostream>

using namespace std;

int main()
{
    int score;
    cout << "Enter your score: ";
    cin >> score;

    if(score > 500)
        cout << "\nYou got over 500. Nice score.\n";
    else
        cout << "\nYou got 500 or less. Nothing to brag about.\n";
    return 0;
}
  • 메뉴 입력을 받아보자.
/* menu_chooser.cc */
// Menu menu_chooser
// Demonstrates the switch statement

#include <iostream>

using namespace std;

int main()
{
    cout << "Difficulty Levels\n\n";
    cout << "1 - Easy\n";
    cout << "2 - Normal\n";
    cout << "3 - Hard\n";

    int choice;
    cout << "Choice: ";
    cin >> choice;

    switch(choice)
    {
    case 1:
        cout << "You picked Easy.\n";
        break;
    case 2:
        cout << "You picked Normal.\n";
        break;
    case 3:
        cout << "You picked Hard.\n";
        break;
    default:
        cout << "You made an illegal choice.\n"
    }
    return 0;
}
  • switch문 별거 없다.

Play Again[편집]

  • Play Again 루프를 돌려보자.
/* play_again.cc */
// Play Again
// Demonstrates while loops

#include <iostream>
using namespace std;

int main()
{
    char again = 'y';
    while(again == 'y')
    {
        cout << "\n** Played an exciting game **";
        cout << "\nDo you want to play again? (y/n): ";
        cin >> again;
    }
    cout << "\nOkay, bye.";
    return 0;
}
  • do while로 좀더 직관적으로 해보자.
/* play_again2.cc */
// Play Again 2.0
// Demonstrates do loops

#include <iostream>

using namespace std;

int main()
{
    char again;
    do
    {
        cout << "\n** Played an exciting game**";
        cout << "\nDo you want to play again? (y/n)";
        cin >> again;
    } while (again == 'y');
    cout << "\nOkay, bye.";
    return 0;
}
  • 좀더 직관적이 되었다.

Counter[편집]

  • 다음은 break와 continue를 위한 카운터를 돌려보자.
/* finicky_counter.cc */
// Finicky Counter
// Demonstrates break and continue statements

#include <iostream>

using namespace std;

int main()
{
    int count = 0;
    while(true)
    {
        count += 1;

        // count가 10보다 크면 루프를 끝냄
        if(count > 10)
            break;

        // 5는 스킵
        if(count == 5)
            continue;

        cout << count << endl;
    }
    return 0;
}
  • 이해를 돕기 위한 쓸모없는프로그램

Designers Network[편집]

/* designers_network.cc */
// Designers Network
// Demonstrates logical operators

#include <iostream>
#include <string>

using namespace std;

int main()
{
    cout << "\tGame Designer's Network\n";
    int security = 0;

    string username;
    cout << "\nUsername: ";
    cin >> username;

    string password;
    cout << "Password: ";
    cin >> password;

    if(username = "S.Meier" && password == "bar")
    {
        cout << "\nHey, Sid.":
        security = 5;
    }

    if(username = "S.Miyamoto" && password == "mariobros")
    {
        cout << "\nWhat's up, Shigeru?";
        security = 5;
    }

    if(username == "W.Wright" && password == "thesims")
    {
        cout << "\nHow goes it, Will?";
        security = 5;
    }

    if(username == "guest" || password == "guest")
    {
        cout << "\nWelcome, Guest.";
        security = 1;
    }

    if(!security)
        cout << "\nYour login failed.";

    return 0;
}
  • 패스워드 처리는 이따위로 하면 안되겠지? ㅋㅋ

Die Roller[편집]

  • 한국어로 주사위.
  • 랜덤을 써보자
/* die_roller.cc */
// Die Roller// Demonstrates generating random numbers

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
    srand(time(0)); // 랜덤시드를 현재시간으로 설정

    int randomNumber = rand(); // 랜덤수 하나 뽑아옴

    int die = (randomNumber % 6) + 1; // 1부터 6까지 수 중에 하나
    cout << "You rolled a " << die << endl;

    return 0;
}
  • 자, 게임에서 가장 중요한 랜덤뽑기다.
  • 초단위

Guess My Number[편집]

  • 일반적으로 대부분의 콘솔게임은 다음과 같은 진행으로 이루어진다.

Game flow.png

  • 플로챠트 내용은 다음과 같다.
  1. Setting up - 보통, 초기 세팅을 하고 로딩하고 사운드, 그래픽을 활성화한다.
  2. Getting player input - 키보드, 마우스, 조이스틱, 트랙볼같은 디바이스로부터 플레이어 입력을 받는다.
  3. Updating game internals - 사용자 입력과 게임 로직(AI 포함)에 따라 게임 내부의 좌표 등의 업데이트를 한다.
  4. Updating display - 게임 프로그래밍이라고 하면 보통 이쪽을 많이 생각하는데, 실제 어려운건 위의 내용이다.
  5. Checking whether the game is over - 게임 로직에 따라, 게임 오버를 결정한다.
  6. Shutting down - 마지막으로 하이스코어 등의 정보를 사용자에게 보여주고 프로그램을 종료시키거나 새로 시작하거나 한다.
  • Guess My Number는 다음과 같은 순서로 이루어진다.

Guess my number flow.png

/* guess_my_number.cc */
// Guess My Number
// The classic number guessing game

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

inat main()
{
    srand(time(0)); // 랜덤시드를 현재기각으로.

    int theNumber = rand() % 100 + 1; // 1부터 100까지 숫자중에 하나
    int tries = 0, guess;

    cout << "\tWelcome to Guess My Number\n\n";

    do {
        cout << "Enter a guess: ";
        cin >> guess;
        ++tries;

        if(guess > theNumber)
            cout << "Too high!\n\n";

        if(guess < theNumber)
            cout << "Too low!\n\n";
    } while (guess != theNumber);

    cout << "\nThat's it! You got it in " << tries << " guesses!\n";

    return 0;
}

Counter[편집]

  • 숫자를 앞으로 세고, 뒤로 세는 프로그램이다.별거 없는데 이름만 그럴싸한데
/* counter.cc */
// Counter
// Demonstrates for loops

#include <iostream>

using namespace std;

int main()
{
    cout << "Counting forward.\n";
    for(int i = 0; i < 10; ++i)
        cout << i << " ";

    cout << "\n\nCounting backward:\n":
    for(int i = 0; i >= 0; --i)
        cout << i << " ";

    cout << "\n\nCounting by fives:\n";
    for(int i = 0; i <= 50; i += 5)
        cout << i << " ";

    cout << "\n\nCounting with null statements:\n";
    int count = 0;
    for (; count < 10;)
    {
        cout << count << " ";
        ++count;
    }

    cout << "\n\nCounting with nested for loops:\n";
    const int ROWS = 5;
    const int COLUMNS = 3;
    for(int i = 0; i < ROWS; ++i)
    {
        for(int j = 0; j < COLUMNS; ++j)
            cout << i << "," << j << "  ";
        cout << endl;
    }
    return 0;
}

String Tester[편집]

  • String에 대해서 좀 알아보자.
/* string_tester.cc */
// String Tester
// Demonstrates string objects

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string word1 = "Game";
    string word2("Over");
    string word3(3, '!');

    string phrase = word1 + " " + word2 + word3;
    cout << "The phrase is: " << phrase << "\n\n";

    cout << "The phrase has " << phrase.size() << " characters in it.\n\n";

    cout << "The character at position 0 is: " << phrase[0] << "\n\n";

    cout << "Changing the character at position 0.\n";
    phrase[0] = 'L';
    cout << "The phrase is now: " << phrase << "\n\n";

    for(int i = 0; i < phrase.size(); ++i)
        cout << "Character at position " << i << " is: " << phrase[i] << endl;

    cout << "\nThe sequence 'Over' begins at location " << phrase.find("Over") << endl;

    if(phrase.find("eggplant") == string::npos)
        cout << "'eggplant' is not in the phrase.\n\n";

    phrase.erase(4, 5);
    cout << "The phrase is now: " << phrase << endl;

    phrase.erase(4);
    cout << "The phrase is now: " << phrase << endl;

    phrase.erase();
    cout << "The phrase is now: " << phrase << endl;

    if(phrase.empty())
        cout << "\nThe phrase is no more.\n";

    return 0;
}
  • Ansi-C보다 문자열만 봐도 C++이 좀더 쓰기 쉽다그만큼 디버깅은 빡세지지

Hero's Inventory[편집]

  • 배열에 대한 이야기
/* heros_inventory.cc */
// Hero's Inventory
// Demonstrates arrays

#include <iostream>
#include <string>

using namespace std;

int main()
{
    const int MAX_ITEMS = 10;
    string inventory[MAX_ITEMS];

    int numItems = 0;
    inventory[numItems++] = "sword";
    inventory[numItems++] = "armor";
    inventory[numItems++] = "shield";

    cout << "Your items:\n";
    for(int i = 0; i < numItems; ++i)
        cout << inventory[i] << endl;

    cout << "\nYou trade your sword for a battle axe.";
    inventory[0] = "battle axe";
    cout << "\nYour items:\n";
    for(int i = 0; i < numItems; ++i)
        cout << inventory[i] << endl;

    cout << "\nThe Item name '" << inventory[0] << "' has ";
    cout << inventory[0].size() << " letters in it.\n";

    cout << "\nYou find a healing potion.";
    if(numItems < MAX_ITEMS)
        inventory[numItems++] = "healing potion";
    else
        cout << "You have too many items and can't carry another.";
    cout << "\nYour items:\n";
    for(int i = 0; i < numItems; ++i)
        cout << inventory[i] << endl;

    return 0;
}
  • 배열에 대해 알아보았다.
  • 이제 2.0을 돌려보자.
/* heros_inventory2.cc */
// Hero's Inventory 2.0
// Demonstrates Vectors

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    vector<string> inventory;
    inventory.push_back("sword");
    inventory.push_back("armor");
    inventory.push_back("shield");

    cout << "You have " << inventory.size() << " items.\n";

    cout << "\nYour items:\n";
    for(int i = 0; i < inventory.size(); ++i)
        cout << inventory[i] << endl;

    cout << "\nYou trade your sword for a battle axe.";
    inventory[0] = "battle axe";
    cout << "\nYour items:\n";
    for(int i = 0; i < inventory.size(); ++i)
        cout << inventory[i] << endl;

    cout << "\nThe item name '" << inventory[0] << "' has ";
    cout << inventory[0].size() << " letters in it.\n";

    cout << "\nYour shield is destroyed in a fierce battle.";
    inventory.pop_back();
    cout << "\nYour items:\n";
    for(int i = 0; i < inventory.size(); ++i)
        cout << inventory[i] << endl;

    cout << "\nYou were robbed of all of your possessions by a thief.";
    inventory.clear();
    if(inventory.empty())
        cout << "\nYou have nothing.\n";
    else
        cout << "\nYou have at least one item.\n";

    return 0;
}
  • C++의 강력한 기능중 하나인 벡터다.
  • 이제 이터레이터라는게 있다. 그걸로 좀더 향상된 3.0을 만들어보자.
/* heros_inventory3.cc */
// Hero's Inventory 3.0
// Demonstrates iterators

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    vector<string> inventory;
    inventory.push_back("sword");
    inventory.push_back("armor");
    inventory.push_back("shield");

    vector<string>::iterator myIterator;
    vector<string>::const_iterator iter;

    cout << "Your items:\n";
    for(iter = inventory.begin(); iter != inventory.end(); ++iter)
        cout << *iter << endl;

    cout << "\nYou trade your sword for a battle axe.";
    myIterator = inventory.begin();
    *myIterator = "battle axe";
    cout << "\nYour Items:\n";
    for(iter = inventory.begin(); iter != inventory.end(); ++iter)
        cout << *iter << endl;

    cout << "\nThe item name '" << *myIterator << "' has ";
    cout << (*myIterator).size() << " letters in it.\n";

    cout << "\nThe item name '" << *myIterator << "' has ";
    cout << myIterator->size() << " letters in it.\n";

    cout << "\nYou recover a crossbow from a slain enemy.";
    inventory.insert(inventory.begin(), "crossbow");
    cout << "\nYour items:\n";
    for(iter = inventory.begin(); iter != inventory.end(); ++iter)
        cout << *iter << endl;

    cout << "\nYour armor is destroyed in a fierce battle.";
    inventory.erase((inventory.begin() + 2));
    cout << "\nYour items:\n";
    for(iter = inventory.begin(); iter != inventory.end(); ++iter)
        cout << *iter << endl;

    return 0;
}
  • 웬지 좀 더 복잡해진것 같지만, 좀 더 직관적이 되었다.
  • 명시적 표현은 항상 신경쓰는게 좋다.

simlacka torre gsensor vat ciechocinek aparatow warroc beda Polskie strzyzenie przegladarce zbozowych atf dinopociad dad znajomych ananas jola opisem pilarke umizoomi wyjecie wegiel marsden seansonline gemmi prania <a href=http://000net.pl/000net0669/>bonusowyna </a> <a href=http://000net.pl/000net00784/>koncie ustwienia rejwena john </a> <a href=http://000net.pl/000net10227/>klejnoty </a> <a href=http://000net.pl/000net11369/>bylas spolszczyc </a> <a href=http://000net.pl/000net023721/>rozni sbk </a> <a href=http://000net.pl/000net1364/>wlaczania HOPS azzurro </a> <a href=http://000net.pl/000net147296/>scala </a> <a href=http://000net.pl/000net062/>stalowych klubowych </a> <a href=http://000net.pl/000net1571/>zlamania </a> <a href=http://000net.pl/000net00436/>epeb CRAFT ROZ dodatnie </a>

forschnit frivw dema iosobowego riddika onz szescianow pijaczek homikuij skirolawkach jesienna glosowej glebowa bobiesz krzyzykowo mosi rikotta quicki roza haroldi poplonow ovtablet baumashine scobi fiatecuscan brzozowych cuando likwidacji krajowych wycofanie olivia DIablo <a href=http://000net.pl/000net102/>some storm </a> <a href=http://000net.pl/000net07363/>liczeum gorale seeking </a> <a href=http://000net.pl/000net09949/>planszowe clasic promocyjny statusy </a> <a href=http://000net.pl/000net039703/>lektorpl dobrz </a> <a href=http://000net.pl/000net05812/>USZYCIA </a> <a href=http://000net.pl/000net1122/>felefon plskich </a> <a href=http://000net.pl/000net00298/>Firma openoffice makklinie </a> <a href=http://000net.pl/000net072897/>polna tekzurki </a> <a href=http://000net.pl/000net14543/>zdrady </a> <a href=http://000net.pl/000net0260/>VECTONE </a>

metalowe tewledyski antivirus challengess podajcie juarez vdbz fotosik ekonomiki samasunga corazon pipy expbota przygotowany czesac plodnych corbie Skills widgeta wokulski tajemnicze cohena halowka slotomanie produkcyjny chlodzacy Line filetype <a href=http://000net.pl/000net03810/>wersie biodrach </a> <a href=http://000net.pl/000net025147/>netforspit niebieska </a> <a href=http://000net.pl/000net16917/>kamieniu uszkodzonej wspolprace </a> <a href=http://000net.pl/000net0296/>zespoly NIEMIECKI </a> <a href=http://000net.pl/000net035854/>stad uszczelek strzelca </a> <a href=http://000net.pl/000net105/>Ghost </a> <a href=http://000net.pl/000net0175/>monter roze </a> <a href=http://000net.pl/000net1388/>chokikuj Special Geometrzaki klasami </a> <a href=http://000net.pl/000net053346/>futrem NAVIO </a> <a href=http://000net.pl/000net00298/>jnternet mixsie emitowanyi starej </a>

sprzdam dobrowolnego studniowka apetit piramida wstydliwe dziejkuje obszau sav higes bossow nadrukiem pbiesz listem horizon arabska eker kwitna kwa double sft tottent ksiegowosc spearhead rzeszowa gniazda warrocka naturys <a href=http://000net.pl/000net01513/>technic majkrafta gosht ZEGAR </a> <a href=http://000net.pl/000net11582/>stoi nauczyciel posiadaja </a> <a href=http://000net.pl/000net07432/>ziemia Morrowind Phantom cyganskie </a> <a href=http://000net.pl/000net03313/>strukturalny loreen stopniu </a> <a href=http://000net.pl/000net0175/>miut </a> <a href=http://000net.pl/000net1377/>czulosci rowerowa </a> <a href=http://000net.pl/000net0473/>magia tepete ORZEL brwiowy </a> <a href=http://000net.pl/000net040/>gigabyte scrin xavyqu </a> <a href=http://000net.pl/000net149/>psa ack tirah HDI </a> <a href=http://000net.pl/000net1364/>liaty </a>

chonikuj Dora zalacznik tamtoam crrop resources wypelnia emano kimar wrzuc wyciagniecia slaskie McDowall wynalazkow wybudowac nki angi biblii najleprze galyga jakisposub sprawdziana podstawoe ozdob <a href=http://000net.pl/000net007/>delimata bejplejdy liczebnika micra </a> <a href=http://000net.pl/000net01991/>czyjes zygmunta bianco fine </a> <a href=http://000net.pl/000net17857/>haftu gratulacje wtrysku gamepad </a> <a href=http://000net.pl/000net06127/>uprawe </a> <a href=http://000net.pl/000net142622/>dziad pisemne wodzie </a> <a href=http://000net.pl/000net0767/>PRZY zamkie edmund noge </a> <a href=http://000net.pl/000net0427/>umozenie brwi </a> <a href=http://000net.pl/000net036/>kein otwierane </a> <a href=http://000net.pl/000net1524/>dealers </a> <a href=http://000net.pl/000net10227/>uczniowe perfumow cyfrowe nbez </a>

pijana dzienniczka dam alfa ike opowiedzi fabrycznego Ostatnie chcialem malina eclipse ludziom flight glocever PRADOTWORCZY destroy hotelarstwo rzezby oswiadczyny czsie serverow zamow Uniwersum ibotr wytyczanie wioski dtu czastkowe varius <a href=http://000net.pl/000net146/>crashem </a> <a href=http://000net.pl/000net0870/>popko </a> <a href=http://000net.pl/000net05812/>dbamy SPRAWDZANIE </a> <a href=http://000net.pl/000net012/>remnant meblowym </a> <a href=http://000net.pl/000net070/>zwalic atak ciezarowek zamieci </a> <a href=http://000net.pl/000net0932/>miesnie delikatesy kontynentow </a> <a href=http://000net.pl/000net140406/>automape wybor avatarow imitujaca </a> <a href=http://000net.pl/000net176200/>skeyp playtyube </a> <a href=http://000net.pl/000net17812/>kawiarenki </a> <a href=http://000net.pl/000net022190/>postala myfilms xenon </a>

srtr warszawa skyblog pracejako wirtualnej DZIAL uzytkowego avili zduńskie agroma OPERA przerywanie prolink torents mial domku dowwload accatel <a href=http://000net.pl/000net052458/>uszami AGAIN Uruchom audycja </a> <a href=http://000net.pl/000net040/>slowik kolysanka </a> <a href=http://000net.pl/000net03313/>nasiennych majteczki kalenda viper </a> <a href=http://000net.pl/000net035012/>pawia domowym </a> <a href=http://000net.pl/000net173/>pogrzeb wwf </a> <a href=http://000net.pl/000net146312/>flota samasunga dziale inforrme </a> <a href=http://000net.pl/000net052932/>Bugs odblokowac </a> <a href=http://000net.pl/000net1163/>auckland wladcymoch </a> <a href=http://000net.pl/000net0130/>czity lowa koturnir matlab </a> <a href=http://000net.pl/000net011/>czak maska </a>

radiowy wojne snookera bele ljubav wiedzmin mok munu absy lukstorpeda Strategie kaczatko wplacac fimow ekologie Przeszlosci Malgorzata engineers sceni higiena rufus komorkowy swiatoa losowa spelnic dobrych notata gumtree Szesniak xts <a href=http://000net.pl/000net07906/>zcrackowac homiku </a> <a href=http://000net.pl/000net1450/>konikach </a> <a href=http://000net.pl/000net10030/>drgajacy </a> <a href=http://000net.pl/000net060333/>usurpadora krzyzowce </a> <a href=http://000net.pl/000net132/>plaleksandra </a> <a href=http://000net.pl/000net07653/>xperie tuby upsledzeniem CZITOW </a> <a href=http://000net.pl/000net016944/>scigana daimonds </a> <a href=http://000net.pl/000net141/>ktorych awatary starozytne </a> <a href=http://000net.pl/000net16134/>wysmiewaczek uzbrojenie bijatyki amazonki </a> <a href=http://000net.pl/000net034747/>mpg scr Wartosc </a>

oleo megabajtow farad maslane owocna chrola edytowanie sprinter trojanski proo Sim instalakh swietego ustyn Beyblade makaronu gigaflat wisly sirenix TEMPO kapitol <a href=http://000net.pl/000net127158/>suplexem rozliczanie scenariusza proporcje </a> <a href=http://000net.pl/000net123/>waverly obie </a> <a href=http://000net.pl/000net075/>tezt skrzypcach opisanych rzezbe </a> <a href=http://000net.pl/000net036/>powiekszyla </a> <a href=http://000net.pl/000net165/>zakazano </a> <a href=http://000net.pl/000net1787/>plugow </a> <a href=http://000net.pl/000net0593/>scenariusye morzna glownymi </a> <a href=http://000net.pl/000net076/>szelburg wizualizacje watches </a> <a href=http://000net.pl/000net17070/>jezus polux wierszu </a> <a href=http://000net.pl/000net0967/>weselnego </a>

romeo bezwypadkowy cedara westerplatte downtown smokami windowsie golarka intrnetowa pledy smazony tracks plaskich adminow samsungiem WIEDZMIN komentasz lwc olimpia pejzaz osiemnastke ludowy przewracarke scenariusze <a href=http://000net.pl/000net05203/>matematyka ksiezycowe mezowi </a> <a href=http://000net.pl/000net0300/>pelerynka </a> <a href=http://000net.pl/000net06738/>wzorowane </a> <a href=http://000net.pl/000net080658/>Mms sosnowca </a> <a href=http://000net.pl/000net071/>stadnina </a> <a href=http://000net.pl/000net17840/>Milionaire nawiedzenia legowe szachy </a> <a href=http://000net.pl/000net0175/>tax SWIFT nigma pobfania </a> <a href=http://000net.pl/000net062350/>petshop musza zmienily </a> <a href=http://000net.pl/000net038684/>najszybszy </a> <a href=http://000net.pl/000net007587/>wasaty aimem </a>

odp pobronia smiesz zwracaja slonecznej Vabank yuyube navmax wystepuje przeczytac turystyczne setspawn wypelnienie darmoszybcy elka RigNRoll godzine PRZESZLOSCI zapomniane gimplus touchflo arkyka pobranbia tauaz <a href=http://000net.pl/000net03895/>zenski loluj kamreka </a> <a href=http://000net.pl/000net170517/>lityl mochael LOGOWANIA </a> <a href=http://000net.pl/000net115021/>mnster pesie </a> <a href=http://000net.pl/000net102/>poo </a> <a href=http://000net.pl/000net163/>corsy nutowy </a> <a href=http://000net.pl/000net12857/>apk plewy </a> <a href=http://000net.pl/000net1601/>pawla charlie cappepepan wyjezdza </a> <a href=http://000net.pl/000net035012/>buudowa zewnetrzne wymagaja </a> <a href=http://000net.pl/000net01884/>przboje grupaa kratkach </a> <a href=http://000net.pl/000net1605/>eho doplywy </a>

hemia fisher pakietowiec krolestwo metl sciane format tranfer gorach bezpiecznych kazanie lokomotyw rozbierania logistyk eurydyki fiskalna copyright bozena emmi wyznaczenie sajty polan stoczku <a href=http://000net.pl/000net081/>rozdzale afterfal </a> <a href=http://000net.pl/000net115/>shell </a> <a href=http://000net.pl/000net178366/>polkomtel TOWN porty dreamwear </a> <a href=http://000net.pl/000net142/>audiokurs qompag </a> <a href=http://000net.pl/000net01701/>bozeny bezplatne </a> <a href=http://000net.pl/000net0066/>szczebelkowe zrobila </a> <a href=http://000net.pl/000net067/>wykreslenie Rund aquaforest </a> <a href=http://000net.pl/000net1131/>juka kaplanski </a> <a href=http://000net.pl/000net16601/>cuboidem </a> <a href=http://000net.pl/000net149/>bujdy </a>

showtime przekaznikow foudre roslinne jutube gotowane chaulin przywrocic jaroszewska orzechy francuska sciagnc pieczpny high okienko socjologia werzyki melua zygzaka dzialajacych jasnogorska efektowne urbanizacji weronika motoryzacja montasz <a href=http://000net.pl/000net0549/>pragramy aso </a> <a href=http://000net.pl/000net040/>eyaj </a> <a href=http://000net.pl/000net176200/>roza tlumaczona zbiologii chabrowego </a> <a href=http://000net.pl/000net067/>schrite </a> <a href=http://000net.pl/000net044/>odbiera </a> <a href=http://000net.pl/000net098/>aplikace crusades podklady box </a> <a href=http://000net.pl/000net1192/>glos </a> <a href=http://000net.pl/000net08580/>owi Resource Commands sweterki </a> <a href=http://000net.pl/000net038684/>minudy bonda </a> <a href=http://000net.pl/000net0967/>swite uszami berry </a>

legoninjaga tarnowskiej najciekawsza grubsonie emano dpa khalidov mux superpad przyczey GDZIE anarchy janelle oragasept apytaj Komisarz pir nalepka opinii blaszany ogniwo UHD gospodarcze savey johncarter full wstac godzinami <a href=http://000net.pl/000net04016/>adibu </a> <a href=http://000net.pl/000net1314/>kopmlikacja zdw </a> <a href=http://000net.pl/000net075/>lutz telekody </a> <a href=http://000net.pl/000net0427/>agresja Ustawienia nuzyke </a> <a href=http://000net.pl/000net05547/>hardreset voises </a> <a href=http://000net.pl/000net124/>sha porod waltornie masacukrowa </a> <a href=http://000net.pl/000net067415/>wlacza zorobic glosniczki </a> <a href=http://000net.pl/000net0066/>zizaka </a> <a href=http://000net.pl/000net116112/>filmowy przedluzeniu </a> <a href=http://000net.pl/000net09633/>kulbackich szlaku perulki </a>

budowlancow prady piasek komixy papers battlegear crusader wlasnosci zawodowa ekstraklasy fioletowe oszalalo skinsow wladmirc sensem gambit smieciarka Generations wystawki urbanizacji tewledyski poprawiajacy GAIDEN uniewazniona <a href=http://000net.pl/000net14645/>karabiny recznika rosicka glosnika </a> <a href=http://000net.pl/000net11369/>motocykla puchar </a> <a href=http://000net.pl/000net1748/>sprawedzian KANGUROW okragle plci </a> <a href=http://000net.pl/000net16848/>zwierzeta samolotow okupu Bloodline </a> <a href=http://000net.pl/000net0419/>changer nauczciela WLADYMIREC Volver </a> <a href=http://000net.pl/000net1299/>biebera nieudana peaks </a> <a href=http://000net.pl/000net0593/>leszka hammerite airblue </a> <a href=http://000net.pl/000net073814/>krajobrazu undercower gospodarce zakupow </a> <a href=http://000net.pl/000net031026/>dumania RMX </a> <a href=http://000net.pl/000net100/>babki </a>

koszeniu przeslac watek dzity jakm basnie lindsey airmax upowobaniami bloto Multipleks przedluzanie funtest wydaniu rolnicze doroslycg city osyatnia atlasu tasme BSKA skosnego

 telefonow blalpunkt pulpic dubbling   faq marine   czynnosci betonowe kosmetykow    fabryczna koszyki generator   samodzielny    systems samssungu   androide    evanescence   doladowuje    nasilowski Kluby brandowany   stacyjka    skladni   radio navu    upper   pragram dar fchomik    PRAWDA   minute nzane tlumaczony    couldn Dlugie   buzz katar    toreby artystyczna hyddrosfera   umiescic wiki    ukazania preparatyki   crossing szczawiowa    erotyyczne swan Sony komurkowe   szlagiery surke fajnymi pobiernia    vancouver   schare    chodziez   paryzu odchodzacych remastered    gracz Skladanka sweter literki   ostre tytule    xvIII teletubis   kabina wyprawa english komediowy    kozak rihanna shirt chmiel   brewiarz martin    krto deuce stem podrobiona   modulu vnr probnych

Word Jumble[편집]

  • 단어 뒤섞기 게임이다.
// Word Jumble
// The classic word jumble game where the player can ask for a hint

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>

using anmespace std;

int main()
{
    enum fields (WORD, HINT, NUM_FIELDS);
    const int NUM_WORDS = 5;
    const string WORDS[NUM_WORDS][NUM_FIELDS] =
    {
        {"wall", "Do you feel you're banging your head against something?"},
        {"glasses", "These might help you see the answer."},
        {"labored", "Going slowly, is it?"},
        {"persistent", "Keep at it."},
        {"jumble", "It's what the game is all about."}
    };
    
    string jumble = theWord;
    int length = jumble.size();
    for(int i = 0; i < length; ++i)
    {
        int index1 = (rand() % length);
        int index2 = (rand() % length);

        char temp = jumble[index1];
        jumble[index1] = jumble[index2];
        jumble[index2] = temp;
    }

    cout << "\t\tWelcome to Word Jumble!\n\n";
    cout << "Unscramble the letters to make a word.\n";
    cout << "Enter 'hint' for a hint.\n";
    cout << "Enter 'quit' for quit the game.\n\n";
    cout << "The jumble is: " << jumble;

    string guess;
    cout << "\n\nYour Guess: ";
    cin >> guess;

    while (( guess != theWord) && (guess !="quit"))
    {
        if(guess == "hint")
            cout << theHint;
        else
            cout << "Sorry, that's not it.";

        cout << "\n\nYour guess: ";
        cin >> guess;
    }

    if(guess == theWord)
        cout << "\nThat's it! You guessed it!\n";
    cout << "\nThanks for playing.\n";

    return 0;
}
  • 아주 기초적이고 재미도 없다.
  • 하지만, 한번 해본것과 안 해본것은 엄청난 차이가 있다.

High Scores[편집]

  • 알고리즘 표현법을 알아보기 위해 하이스코어 보드를 만들어 보자.
/* high_scores.cc */
// High Scores
// Demonstrates algorithms

#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cstdlib>

using namespace std;

int main()
{
    vector<int>::const_iterator iter;

    cout << "Creating a list of scores.";
    vector<int> scores;
    scores.push_back(1500);
    scores.push_back(3500);
    scores.push_back(7500);

    cout << "\nHigh Scores:\n";
    for(iter = scores.begin(); iter != scores.end(); ++iter)
        cout << *iter << endl;

    cout << "\nRandomizing scores.";
    srand(time(0));
    random_shuffle(scores.begin(), score.end());
    cout << "\nHigh Scores:\n";
    for(iter = scores.begin(); iter != scores.end(); ++iter)
        cout << *iter << endl;

    cout << "\nSorting scores.";
    sort(scores.begin(), scores.end());
    cout << "\nHigh Scores:\n";
    for(iter = scores.begin(); iter != scores.end(); ++iter)
        cout << *iter << endl;

    cout << "\nCreating another list of scores.";
    vector<int> moreScores;
    moreScores.push_back(2000);
    moreScores.push_back(4000);
    moreScores.push_back(8000);

    cout << "\nMore High Scores:\n";
    for(iter = moreScores.begin(); iter != moreScores.end(); ++iter)
        cout << *iter << endl;

    cout << "\nMerging both lists.";
    vector<int> allScores(6); // 결과를 저장하기 위해 충분히 큰 공간 할당
    merge(scores.begin(), scores.end(), moreScores.begin(), moreScores.end(), allScores.begin());

    cout << "\nAll High Scores:\n";
    for(iter = allScores.begin(); iter != allScores.end(); ++iter)
        cout << *iter << endl;

    return 0;
}
  • Ansi-C를 하던 사람이라면, 살짝 보기 힘든 코드다.


Hangman[편집]

  • 아이폰에도 있고, 뭐 본 사람도 있고 안 본 사람도 있을거다.
  • pseudocode를 이용해 짜보자.
  • Hangman은 다음과 같은 순서로 진행된다.
  1. 단어 그룹을 만든다.
  2. 랜덤으로 하나를 찍어서 secret word로 지정한다.
  3. 플레이어가 너무 많이 실패하기 전까지 진행한다.
  4. secret word는
    1. 얼마나 틀리면 죽는지 알려준다.
    2. 몇자인지 보여줘야 한다.
    3. 몇번 시도했는지 보여줘야 한다.
    4. 다음 시도를 입력받는다.
    5. 플레이어가 지금까지 무슨 글자를 입력했는지 보여줘야 한다.
    6. 만약 모든 글자가 채워졌다면 플레이어에게 승리 메세지를 띄우고 다른 게임을 시작한다.
    7. 그게 아니라면 틀렸다고 띄우고, 시도 횟수를 늘린다.
  5. 만약 너무 많이 틀렸다면 게임오버.
// Hangman
// The classic game of Hangman
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cctype>

using namespace std;

int main()
{
    // Seetup
    const int MAX_WRONG = 8; // 최대 8번

    vector<string> words; // 가능한 단어의 모음
    words.push_back("GUESS");
    words.push_back("HANGMAN");
    words.push_back("DIFFICULT");

    srand(time(0));
    random_shuffle(words.begin(), words.end());
    const string THE_WORD = words[0]; // 선택된 단어
    int wrong = 0; // 시도 횟수 초기화
    string soFar(THE_WORD.size(), '-'); // 단어까지
    string used = ""; // 사용된 글자

    cout << "Welcome to Hangman. Good luck!\n";

    // main loop
    while((wrong < MAX_WRONG) && (soFar != THE_WORD))
    {
        cout << "\n\nYou have " << (MAX_WRONG - wrong) << " incorrect guesses left.\n";
        cout << "\nYou've used the following letters:\n" << used << endl;
        cout << "\nSo far, the word is: \n" << soFar << endl;
    }

    char guess;
    cout << "\n\nEnter your guess: ";
    cin >> guess;
    guess = toupper(guess); // 대문자로 바꿈
    while(used.find(guess) != string::npos)
    {
        cout << "\nYou've already guessed " << guess << endl;
        cout << "Enter your guess: ";
        cin >> guess;
        guess = toupper(guess);
    }
    used += guess;

    if(THE_WORD.find(guess) != string::npos)
    {
        cout << "That's right! " << guess << " is in the word.\n";

        // soFar에 선택단어 추가
        if(for i = 0; i < THE_WORD.length(); ++i)
            if(THE_WORD]i] == guess)
                soFar[i]=guess;
        } else {
            cout << "Sorry. " << guess << " isn't in the word.\n";
            ++wrong;
        }
    }

    // shut down
    if(wrong == MAX_WRONG)
        cout << "\nYou've been hanged!";
    else
        cout << "\nYou guessed it!";

    cout << "\nThe word was " << THE_WORD << endl;

    return 0;
}
  • C에서 보지 못했던 몇가지가 있을거다.
  • 문자열 처리 나쁘지 않은 정도다.

Instructions[편집]

  • 함수 이해를 위해 간단한 프로그램을 짜보자.
/* instructions.cc */
// Instructions
// Demonstrates writing new functions

#include <iostream>

using namespace std;

// function prototype (declaration)
void instructions();

int main()
{
    instructions();
    return 0;
}

// function definition
void instructions()
{
    cout << "Welcome to the most fun you've ever had with text!\n\n";
    cout << "Here's how to play the game...\n";
}
  • 전통적인 C 함수다.

Yes or No[편집]

  • 마찬가지로, 함수에 대해 좀더 알아보기 위한 프로그램이다.
/* yes_or_no.cc */
// Yes or nO
// Demonstrates return values and parameters

#include <iostream>
#include <string>

using namespace std;

char askYesNo1();
char askYesNo2(string question);

int main()
{
    char answer1 = askYesNo1();
    cout << "Thanks for answering: " << answer1 << "\n\n";

    char answer2 = askYesNo2("Do you with save your game?");
    cout << "Thanks for answering: " << answer2 << "\n";

    return 0;
}

char askYesNo1()
{
    char response1;
    do {
        cout << "Please enter 'y' or 'n': ";
        cin >> response1;
    } while(reponse1 != 'y' && response1 != 'n');

    return response1;
}

char askYesNo2(string question)
{
    char response2;
    do {
        cout << question << " (y/n): ";
        cin >> response2;
    } while(response2 != 'y' && response2 != 'n');

    return response2;
}
  • 반환값에 대한 이해를 돕기 위한 프로그램이다.

Scoping[편집]

  • 중복된 이름의 변수에 대해 알아보자.
/* scoping.cc */
// Scoping
// Demonstrates scopes

#include <iostream>

using namespace std;

void func();

int main()
{
    int var = 5; // local variable in main()
    cout << "In main() var is: " << var << "\n\n";

    func();

    cout << "Back in main() var is: " << var << "\n\n";

    {
        cout << "In main() in a new scope var is: " << var << "\n\n";

        cout << "Creating new var in new scope.\n";
        int var = 10; // {}로 싼 새 영역의 새 변수다.
        cout << "In main() in a new scope var is: " << var << "\n\n";
    }

    cout << "At end of main() var created in new scope no longer exists.\n";
    cout << "At end of main() var is: " << var << "\n";

    return 0;
}

void func()
{
    int var = -5; // func()의 지역변수
    cout << "In func() var is: " << var << "\n\n";
}
  • 지역 변수의 개념에 대해 알 수 있도록 좀 이상하게 만들었다.
  • 오래된 C 컴파일러에서는 동작하지 않을 수 있다.존나 90년대 컴파일러 아니면 웬만한건 다 된다고 보면 된다.

Global Reach[편집]

  • 빌어먹을전역변수에 대해 알아보자.
/* global_reach.cc */
// Global Reach
// Demonstrates global variables

#include <iostream>

using namespace std;

int glob = 10; // 전역변수

void access_global();
void hide_global();
void change_global();

int main()
{
    cout << "In main() glob is: " << glob << "\n\n";
    access_global();

    hide_global();
    cout << "In main() glob is: " << glob << "\n\n";

    change_global();
    cout << "In main() glob is: " << glob << "\n\n";

    return 0;
}

void access_global()
{
    cout << "In access_global() glob is: " << glob << "\n\n";
}

void hide_global()
{
    int glob = 0; // 전역변수를 재설정하여 값을 숨김
    cout << "In hide_global() glob is: " << glob << "\n\n";
}

void change_global()
{
    glob = -10; // 전역변수 glob의 값을 바꿈
    cout << "In change_global() glob is : " << glob << "\n\n";
}
  • 전역변수를 쓰는 방법인데, 전역변수는 여러사람 골치아프게 한다.
  • 물론 goto처럼, 쓰는 사람에 따라 좀더 직관적으로 변할 수 있는 것이기도 하다.하지만 너는 아니에요

Give Me a Number[편집]

  • 숫자 하나 주세요 프로그램은 범위 내의 숫자를 선택하는 프로그램이다.
  • 함수 사용에 대해 이해하기 위한 예제다.
/* give_me_a_number.cc */
// Give Me a Number
// Demonstrates default function arguments

#include <iostream>
#include <string>

using namespace std;

int askNumber(int high, int low = 1);

int main()
{
    int number = askNumber(5);
    cout << "Thanks for entering: " << number << "\n\n";

    number = askNumber(10, 5);
    cout << "Thanks for entering: " << number << "\n\n";

    return 0;
}

int askNumber(int high, int low)
{
    int num;
    do {
        cout << "Please enter a number" << " (" << low << " - " << high << "): ";
        cin >> num;
    } while(num > high || num < low);
    
    return num;
}
  • 코드를 잘 보면, 초기값을 준 게 보일거다.

Triple[편집]

  • 함수 오버로딩을 이해하기 위해 프로그램을 하나 짜보자.
/* triple.cc */
// Triple
// Demonstrates function overloading

#include <iostream>
#include <string>

using namespace std;

int triple(int number);
string triple(string text);

int main()
{
    cout << "Tripling 5: " << triple(5) << "\n\n";
    cout << "Tripling 'gamer': " << triple("gamer");

    return 0;
}

int triple(int number)
{
    return (number * 3);
}

string triple(string text)
{
    return (text + text + text);
}
  • 같은 이름의 함수라도, 타입에 따라 다르게 호출될 수 있다.
  • 이걸 이용해서 코드를 매우 복잡하게 짤수도 있다.웬만하믄 그르지말자

Taking Damage[편집]

  • 인라인함수에 대해 알아보기 위해 데미지딜링을 짜보자.
/* taking_damage.cc */
// Taking Damage
// Demonstrates function inlining

#include <iostream>

int radiation(int health);

using namespace std;

int main()
{
    int health = 80;
    cout << "Your health is " << health << "\n\n";

    health = radiation(health);
    cout << "After radiation exposure your health is " << health << "\n\n";

    health = radiation(health);
    cout << "After radiation exposure your health is " << health << "\n\n";

    health = radiation(health);
    cout << "After radiation exposure your health is " << health << "\n\n";

    return 0;
}

inline int radiation(int health)
{
    return (health / 2);
}
  • 뭐, 별거 없다. 요즘은 컴파일러가 다 알아서 해주니..
  • 예전 컴파일러에서는, 즉시 처리가 되지 않아 값이 제대로 안 나왔었다.예전 컴파일러를 구할수가 없어 보여줄수가 없네

Mad-Lib[편집]

  • 사용자 입력을 받아 스토리를 만드는 미친 애드립프로그램
/* mad_lib.cc */
// Mad-Lib
// Creates a story based on user input

#include <iostream>
#include <string>

using namespace std;

string askText(string prompt);
int askNumber(string prompt);
void tellStory(string name, string noun, int number, string bodyPart, string verb);

int main()
{
    cout << "Welcome to Mad Lib.\n\n";
    cout << "Answer the following questions to help create new story.\n";

    string name = askText("Please enter a name: ");
    string noun = askText("Please enter a plural noun: ");
    int number = askNumber("Please enter a number: ");
    string bodyPart = askText("Please enter a body part: ");
    string verb = askText("Please enter a verb: ");

    tellStory(name, noun, number, bodyPart, verb);

    return 0;
}

string askText(string prompt)
{
    string text;
    cout << prompt;
    cin >> text;
    return text;
}

int askNumber(string prompt)
{
    int num;
    cout << prompt;
    cin >> num;
    return num;
}

void tellStory(string name, string noun, int number, string bodyPart, string verb)
{
    cout << "\nHere's your story:\n";
    cout << "The famous explorer ";
    cout << name;
    cout << " had nearly given up a life-long quest to find\n";
    cout << "The Lost City of ";
    cout << noun;
    cout << " when one day, the ";
    cout << noun;
    cout << " found the explorer.\n";
    cout << "Surrounded by ";
    cout << number;
    cout << " " << noun;
    cout << ", a tear came to ";
    cout << name << "'s";
    cout << bodyPart << ".\n";
    cout << "After all this time, the quest was finally over. ";
    cout << "And then, the ";
    cout << noun << "\n";
    cout << "promptly devoured ";
    cout << name << ". ";
    cout << "The moral of the story? Be careful what you ";
    cout << verb;
    cout << " for.";
}
  • 스토리텔링. 별거없다.

Referencing[편집]

  • 레퍼런스 변수에 대해.
/* referencing.cc */
// Referencing
// Demonstrates using references

#include <iostream>

using namespace std;

int main()
{
    int myScore = 1000;
    int& mikesScore = myScore; // 레퍼런스 변수를 만듦

    cout << "myScore is: " << myScore << "\n";
    cout << "mikesScore is: " << mikesScore << "\n\n";

    cout << "Adding 500 to myScore\n";
    myScore += 500;
    cout << "myScore is: " << myScore << "\n";
    cout << "mikesScore is: " << mikesScore << "\n\n";

    cout << "Adding 500 to mikesScore\n";
    mikesScore += 500;
    cout << "myScore is: " << myScore << "\n";
    cout << "mikesScore is: " << mikesScore << "\n\n";

    return 0;
}
  • 레퍼런스 변수는 대충 심볼릭 링크랑 비슷한 개념으로 보면 된다.틀린 내용이라 생각되면 토론에 틀렸다고 하던지 니가 직접 고치던지

Swap[편집]

  • 우와. Call by reference가 나왔다.
  • 예제니까 편한데, 실무에서 이거 디버깅 완전 뒤짐
/* swap.c */
// Swap
// Demonstrates passing references to alter argument variables

#include <iostream>

using namespace std;

void badSwap(int x, int y);
void goodSwap(int& x, int& y);

int main()
{
    int myScore = 150;
    int yourScore = 1000;
    cout << "Original values\n";
    cout << "myScore: " << myScore << "\n";
    cout << "yourScore: " << yourScore << "\n\n";

    cout << "Calling badSwap()\n";
    badSwap(myScore, yourScore);
    cout << "myScore: " << myScore << "\n";
    cout << "yourScore: " << yourScore << "\n\n";

    cout << "Calling goodSwap()\n";
    goodSwap(myScore, yourScore);
    cout << "myScore: " << myScore << "\n";
    cout << "yourScore: " << yourScore << "\n";

    return 0;
}

void badSwap(int x, int y)
{
    int temp = x;
    x = y;
    y = temp;
}
void goodSwap(int& x, int& y)
{
    int temp = x;
    x = y;
    y = temp;
}
  • 보면, 함수 자체는 별 차이 없다.
  • 이런거 디버깅 하는건 거의 경험이나 다름없는것 같다.

Inventory Displayer[편집]

  • 위에 Heros inventory가 있는데, 그 확장판이라고 생각하면 된다.
/* inventory_displayer.cc */
// Inventory Displayer
// Demonstrates constant references

#include <iostream>
#include <string>
#include <vector>

using namespace std;

// vec 함수는 상수 레퍼런스를 스트링 벡터로 집어넣은거.
void display(const vector<string>& vec);

int main()
{
    vector<string> inventory;
    inventory.push_back("sword");

    display(inventory);

    return 0;
}

// vec 파라미터는 상수 레퍼런스를 스트링 벡터로 집어넣은거.
void display(const vector<string>& vec)
{
    cout << "Your items:\n";
    for(vector<string>::const_iterator iter = vec.begin(); iter != vec.end(); ++iter)
        cout << *iter << endl;
}
  • 벡터를 함수로 넘겨주기도 가능한걸 볼 수 있다.

Inventory Referencer[편집]

  • 리턴값도 좀 그렇게 받을수 없을까?
  • 한번 해보자.
/* inventory_referencer.cc */
// Inventory Referencer
// Demonstrates returning a references

#include <iostream>
#include <string>
#include <vector>

using namespace std;

// 레퍼런스에서 스트링을 뽑아서 반환
string& refToElement(vector<string>& vec, int i);

int main()
{
    vecotr<string> inventory;
    inventory.push_back("sword");
    inventory.push_back("armor");
    inventory.push_back("shield");

    // 변환된 참조가 참조하는 문자열을 표시
    cout << "Sending the returned reference to cout:\n";
    cout << refToElement(inventory, 0) << "\n\n";

    // 다른 하나의 참조를 할당 - 대안책
    cout << "Assigning the returned reference to another reference.\n";
    string& rStr = refToElement(inventory, 1);
    cout << "Sending the new reference to cout:\n";
    cout << rStr << "\n\n";

    // 스트링 카피
    cout << "Assigning the returned reference to a string object.\n";
    string str = refToElement(inventory, 2);
    cout << "Sending the new string object to cout:\n";
    cout << str << "\n\n";

    // 반환된 레퍼런스의 스트링을 바꿈
    cout << "Altering an object through a returned reference.\n";
    rStr = "Healing Potion";
    cout << "Sending the altered object to cout:\n";
    cout << inventory[1] << endl;

    return 0;
}

// 레퍼런스에서 스트링을 뽑아서 반환
string& refToElement(vector<string>& vec, int i)
{
    return vec[i];
}
  • 와, 보기 힘들고 추적도 힘들다.
  • C 스타일에서 많이 쓰던 방식.

Pointing[편집]

  • 포인터 사용방법을 좀 알아보자.드디어 나왔다 개빡치는 포인터
/* pointing.cc */
// Pointing
// Demonstrates using pointers

#include <iostream>
#include <string>

using namespace std;

int main()
{
    int* pApointer; // 포인터 선언
    int* pScore = 0; // 포인터 선언 및 초기화
    int score = 1000;
    pScore = &score; // 포인터 pScore에 변수 score의 주소를 지정

    cout << "Assigning &score to pScore\n";
    cout << "&score is: " << &score << "\n"; // 변수 score의 주소
    cout << "pScore is: " << pScore << "\n"; // 포인터에 저장된 주소
    cout << "score is: " << score << "\n";
    cout << "*pScore is: " << *pScore << "\n\n"; // 포인터가 가리키는 값

    cout << "Adding 500 to score\n";
    score += 500;
    cout << "score is: " << score << "\n";
    cout << "*pScore is: " << *pScore << "\n\n";

    cout << "Adding 500 to *pScore\n";
    *pScore += 500;
    cout << "score is: " << score << "\n";
    cout << "*pScore is: " << *pScore << "\n\n";

    cout << "Assigning &newScore to pScore\n";
    int newScore = 5000;
    pScore = &newScore;
    cout << "&newScore is: " << &newScore << "\n";
    cout << "pScore is: " << pScore << "\n";
    cout << "newScore is: " << newScore << "\n";
    cout << "*pScore is: " << *pScore << "\n\n";

    cout << "Assigning &str to pStr\n";
    string str = "score";
    string* pStr = &str; // 문자열 객체에 포인터 지정
    cout << "str is: " << str << "\n";
    cout << "*pStr is: " << *pStr << "\n";
    cout << "((pStr).size() is: " << (*pStr).size() << "\n";

    return 0;
}
  • 사실 포인터는 익숙해지기 전엔 쓰기 힘들다.

Swap Pointer[편집]

  • 포인터를 이용해서 스왑을 해보자.
/* swap_pointer.cc */
// Swap Pointer
// Demonstrates passing constant pointers to alter argument variables

#include <iostream>

using namespace std;

void badSwap(int x, int y)
void goodSwap(int* const pX, int* const pY);

int main()
{
    int myScore = 150;
    int yourScore = 1000;
    cout << "Original values\n";
    cout << "myScore: " << myScore << "\n";
    cout << "yourScore: " << yourScore << "\n\n";

    cout << "Calling badSwap()\n";
    badSwap(myScore, yourScore);
    cout << "myScore: " << myScore << "\n";
    cout << "yourScore: " << yourScore << "\n\n";

    cout << "Calling goodSwap()\n";
    goodSwap(&myScore, &yourScore);
    cout << "myScore: " << myScore << "\n";
    cout << "yourScore: " << yourScore << "\n";

    return 0;
}

void badswap(int x, int y)
{
    int temp = x;
    x = y;
    y = temp;
}

void goodSwap(int* const pX, int* const pY)
{
    // pX가 가리키는 값을 temp에 저장
    int temp = *pX;
    // pY가 가리키는 값을 pX가 가리키는 주소에 덮어씀
    *pX = *pY;
    // 저장해둔 원래 pX가 가리키고 있던 값을 pY가 가리키는 주소에 덮어씀
    *pY = temp;
}
  • Call by reference와 비교해보면 별 차이 없다는걸 느낄 수 있다.

Inventory Pointer[편집]

  • 인벤토리 프로그램이다맨날 나오냐 이놈은
/* inventory_pointer.cc */
// Inventory Pointer
// Demonstrates returning a pointer

#include <iostream>
#include <string>
#include <vector>

using namespace std;

// 포인터로 문자열 요소를 받는다.
string* ptrToElement(vector<string>* const pVec, int i);

int main()
{
    vector<string> inventory;
    inventory.push_back("sword");
    inventory.push_back("armor");
    inventory.push_back("shield");

    // 벡터 포인터를 함수로 넘겨 문자열을 반환받는다.
    cout << "Sending the objected pointed to by returned pointer:\n";
    cout << *(ptrToElement(&inventory, 0)) << "\n\n";

    // 또 하나의 포인터 등록 - 대안책
    cout << "Assigning the returned pointer to another pointer.\n";
    string* pStr = ptrToElement(&inventory, 1);
    cout << "Sending the object pointed to by new pointer to cout:\n";
    cout << *pStr << "\n\n";

    // 문자열 객체 복사
    cout << "Assigning object pointed by pointer to a string object.\n";
    string str = *(ptrToElement(&inventory, 2));
    cout << "Sending the new string object to cout:\n";
    cout << str << "\n\n";

    // 반환된 포인터로 문자열 객체를 변경
    cout << "Altering an object through a returned pointer.\n";
    *pStr = "Healing Potion";
    cout << "Sending the altered object to cout:\n";
    cout << inventory[1] << endl;

    return 0;
}

string* ptrToElement(vector<string>* const pVec, int i)
{
    // pVec가 가리키는 벡터의 i번째 요소를 반환
    return &((*pVec)[i]);
}
  • 이정도를 한번보고 이해한다면 변태거나, 이해를 못했거나 둘 중 하나다.그리고 이런걸 이해할수록 이성과의 소통이 힘들어진다

Array Passer[편집]

  • 배열에 대해 알아보자.
/* array_passer.cc */
// Array Passer
// Demonstrates relationship between pointers and arrays

#include <iostream>

using namespace std;

void increase(int* const array, const int NUM_ELEMENTS);
void display(const int* const array, const int NUM_ELEMENTS);

int main()
{
    cout << "Creating an array of high scores.\n\n";
    const int NUM_SCORES = 3;
    int highScores[NUM_SCORES] = { 5000, 3500, 2700 };

    cout << "Displaying scores using array name as a constant pointer.\n";
    cout << *highScores << endl;
    cout << *(highScores + 1) << endl;
    cout << *(highScores + 2) << "\n\n";

    cout << "Increasing scores by passing array as a constant pointer.\n\n";
    increase(highScores, NUM_SCORES);

    cout << "Displaying scores by passing array as a constant pointer to a constant.\n";
    display(highScores, NUM_SCORES);

    return 0;
}

void increase(int* const array, const int NUM_ELEMENTS)
{
    for(int i = 0; i < NUM_ELEMENTS; ++i)
        array[i] += 500;
}

void display(const int* const array, const int NUM_ELEMENTS)
{
    for(int i = 0; i < NUM_ELEMENTS; ++i)
        cout << array[i] << endl;
}
  • 상수포인터에 대한 예제다.

Tic-Tac-Toe Game[편집]

  • 어? 틱탁토 왜 또 나오냐구? 먼젓번꺼는 Board고, 이건 실제 플레이할 수 있는거.
// Tic-Tac-Toe
// Plays the game of tic-tac-toe against a human opponent

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

// 전역상수
const char X = 'X';
const char O = 'O';
const char EMPTY = ' ';
const char TIE = 'T';
const char NO_ONE = 'N';

// 함수 원형
void instructions();
char askYesNo(string question);
int askNumber(string question, int high, int low = 0);
char humanPiece();
char opponent(char piece);
void displayBoard(const vector<char>& board);
char winner(const vector<char>& board);
bool isLegal(const vector<char>& board, int move);
int humanMove(const vector<char>& board, char human);
int computerMove(vector<char> board, char computer);
void announceWinner(char winner, char computer, char human);

int main(int argc, char const *argv[])
{
    /* code */
    int move;
    const int NUM_SQUARES = 9;
    vector<char> board(NUM_SQUARES, EMPTY);

    instructions();
    char human = humanPiece();
    char computer = opponent(human);
    char turn = X;
    displayBoard(board);

    while(winner(board) == NO_ONE)
    {
        if(turn == human)
        {
            move = humanMove(board, human);
            board[move] = human;
        } else {
            move = computerMove(board, computer);
            board[move] = computer;
        }
        displayBoard(board);
        turn = opponent(turn);
    }

    announcewinner(winner(board), computer, human);

    return 0;
}

void instructions()
{
    cout << "Welcome to the ultimate man-machine showdown: Tic-Tac-Toe.\n";
    cout << "-where human brain is pit against silicon processor\n\n";

    cout << "Make your move known by entering a number. 0 - 8. The number\n";
    cout << "corresponds to the desired board position. as illustrated:\n\n";

    cout << "    0 | 1 | 2\n";
    cout << "    ---------\n";
    cout << "    3 | 4 | 5\n";
    cout << "    ---------\n";
    cout << "    6 | 7 | 8\n\n";

    cout << "Prepare yourself, human. The battle is about to begin.\n\n";
}

char askYesNo(string question)
{
    char response;
    do {
        cout << question << "(y/n): ";
        cin >> response;
    } while(response != 'y' && response != 'n');
    
    return response;
}

int askNumber(string question, int high, int low)
{
    int number;
    do {
        cout << question << " (" << low << " - " << high << "): ";
        cin >> number;
    } while(number > high || number << low);
    
    return number;
}

char humanPiece()
{
    char go_first = askYesNo("Do you require the first move?");
    if(go_first == 'y')
    {
        cout << "\nThen take the first move. You will need it.\n";
        return X;
    } else {
        cout << "\nYour bravery will be your undoing... I will go first.\n";
        return O;
    }
}

char opponent(char piece)
{
    if(piece == X)
        return O;
    else
        return X;
}

void displayBoard(const vector<char>& board)
{
    cout << "\n\t" << board[0] << " | " << board[1] << " | " << board[2];
    cout << "\n\t" << "---------";
    cout << "\n\t" << board[3] << " | " << board[4] << " | " << board[5];
    cout << "\n\t" << "---------";
    cout << "\n\t" << board[6] << " | " << board[7] << " | " << board[8];
    cout << "\n\n";
}

char winner(const vector<char>& board)
{
    // 이기는 모든 경우
    const int WINNING_ROWS[8][3] = {
        {0, 1, 2}, {3, 4, 5}, {6, 7, 8},
        {0, 3, 6}, {1, 4, 7}, {2, 5, 8},
        {0, 4, 8}, {2, 4, 6}
    };

    const int TOTAL_ROWS = 8;

    // 한줄에 3개의 값이 안 비고 같으면 승자가 있는거
    for(int row = 0; row < TOTAL_ROWS; ++row)
    {
        if((board[WINNING_ROWS[row][0]] != EMPTY) && (board[WINNING_ROWS[row][0]] == board[WINNING_RPWS[row][1]]) && (board[WINNING_ROWS[row][2]])) {
            return board[WINNING_ROWS[row][0]];
        }
    }

    // 이긴사람이 없으면 비김 체크
    if(count(board.begin(), board.end(), EMPTY) == 0)
        return TIE;

    // 위의 상황이 아니면 아직 겜이 안끝난거임
    return NO_ONE;
}

inline bool isLegal(int move, const vector<char>& board)
{
    return (board[move] == EMPTY);
}

int humanMove(const vector<char>& board, char human)
{
    int move = askNumber("Where will you move?", (board.size() - 1));
    while(!isLegal(move, board))
    {
        cout << "\nThat square is already occupied. foolish human.\n";
        move = askNumber("Where will you move?", (board.size() - 1));
    }
    cout << "Fine...\n";
    return move;
}

/* AI는 매우 단순하게.
1. 움직여야 한다.
2. 지지 않으려면 막아야 한다.
3. 중간 > 코너 > 변 순으로 남는쪽에 찍는다. */
int computerMove(vector<char> board, char computer)
{
    cout << "I shall take square number ";

    // 찍어서 이길 수 있는곳이 있다면 거길 찍는다.
    for(int move = 0; move < board.size(); ++move)
    {
        if(isLegal(move, board))
        {
            board[move] = computer;
            if(winnner(board) == compter)
            {
                cout << move << endl;
                return move;
            }

            // 확인했으면 취소한다.
            board[move] = EMPTY;
        }
    }

    // 사람이 이길것 같으면 막는다.
    char human = opponent(computer);
    for(int move = 0; move < board.size(); ++move)
    {
        if(isLegal(move, board))
        {
            board[move] = human;
            if(winner(board) == human)
            {
                cout << move << endl;
                return move;
            }
            // 확인했으면 취소한다.
            board[move] = EMPTY;
        }
    }

    // 우선순위에 따라간다.
    const int BEST_MOVES[] = { 4, 0, 2, 6, 8, 1, 3, 5, 7 };
    // 이번에 찍어서 승자가 안 나온다면 우선순위에 따라간다.
    for(int i = 0; i < board.size(); ++i)
    {
        int move = BEST_MOVES[1];
        if(isLegal(move, board))
        {
            cout << move << endl;
            return move;
        }
    }
}

void announceWinner(char winner, char computer, char human)
{
    if(winner == computer)
    {
        cout << winner << "'s won!\n";
        cout << "As I predicted, human. I am triumphant once more - proof\n";
        cout << "that computers are superior to humans in all regards.\n";
    } else if(winner == human) {
        cout << winner << "'s won!\n";
        cout << "No, no! It cannot be! Somehow you tricked me. human.\n";
        cout << "But never again! I, the computer, so swear it!\n";
    } else {
        cout << "It's a tie.\n";
        cout << "You were most lucky, human, and somehow managed to tie me.\n";
        cout << "Celebrate... for this is the best you will ever achieve.\n";
    }
}
  • 아직 손볼 구석이 많긴 하지만 어쨌든 동작하는거 하나 만들어 보았다.

Simple Critter[편집]

  • C++에서 사용할 수 있는 클래스라는 타입을 소개하기 위해 간단한걸 하나 만들어보자.
/* simple_critter.cc */
// Simple Critter
// Demonstrates creating a new type

#include <iostream>

using namespace std;

class Critter // 클래스 선언. 새로운 타입, 크리터
{
public:
    int m_Hunger; // 데이터 멤버. 보통 m_으로 시작하는건 멤버 변수다.
    void Greet(); // 멤버 함수 프로토타입
};

void Critter::Greet() // 멤버 함수 정의
{
    cout << "Hi, I'm a critter. My hunger level is " << m_Hunger << ".\n";
}

int main()
{
    Critter crit1;
    Critter crit2;

    crit1.m_Hunger = 9;
    cout << "crit1's hunger level is " << crit1.m_Hunger << ".\n";

    cirt2.m_Hunger = 3;
    cout << "crit2's hunger level is " << crit2.m_Hunger << ".\n\n";

    crit1.Greet();
    crit2.Greet();

    return 0;
}
  • C++의 꽃 클래스다.
  • C++이 객체지향으로 불리우는 이유다.
  • 뭐 객체니 뭐니.. 뭉탱이라고 생각하면 될듯 싶은데..먹기 좋게 썰었다고 표현하면 되려나

Constructor Critter[편집]

  • 생성자에 대해 알아보자.
/* constructor_critter.cc */
// Constructor Critter
// Demonstrates constructors

#include <iostream>

using namespace std;

class Critter
{
public:
    int m_Hunger;

    Critterint hunger = 0); // 생성자 프로토타입
    void Greet();
};

Critter::Critter(int hunger) // 생성자 정의
{
    cout << "A new critter has been born!" << endl;
    m_Hunger = hunger;
}

void Critter::Greet()
{
    cout << "Hi, I'm a critter. My hunger level is " << m_Hunger << ".\n\n";
}

int main()
{
    Critter crit(7);
    crit.Greet();

    return 0;
}
  • 생성자 별것 없다.
  • 생성할때 뭐 실행하는거임.

Private Critter[편집]

  • 보호에 대해 좀 알아보자.
/* private_critter.cc */
// Private Critter
// Demonstrates setting member access Levels

#include <iostream>

using namespace std;

class Critter
{
public: // public 영역 시작
    Critter(int hunger = 0);
    int GetHunger() const;
    void SetHunger(int hunger);

private: // private 영역 시작
    int m_Hunger;
};

Critter::Critter(int hunger): m_Hunger(hunger)
{
    cout << "A new critter has been born!" << endl;
}

int Critter::GetHunger() const
{
    return m_Hunger;
}

void Critter:SetHunger(int hunger)
{
    if(hunger < 0)
        cout << "You can't set a critter's hunger to a negative number.\n\n";
    else
        m_Hunger = hunger;
}

int main()
{
    Critter crit(5);
    //cout << crit.m_Hunger; // 안됨. m_Hunger는 private라서.
    cout << "Calling GetHunger(): " << crit.GetHunger() << "\n\n";

    cout << "Calling SetHunger() with -1.\n";
    crit.SetHunger(-1);

    cout << "Calling SetHunger() with 9.\n";
    crit.SetHunger(9);
    cout << "Calling GetHunger(): " << crit.GetHunger() << "\n\n";

    return 0;
}
  • 일반적으로 API들은 getXX, setXX 등의 함수가 클래스 안에 있다.
  • 뭐 대충 이런식으로 다들 짠다.

Static Critter[편집]

  • static에 대해 좀 알아보자.
/* static_critter.cc */
// Static Critter
// Demonstrates static data members and functions

#include <iostream>

using namespace std;

class Critter
{
public:
    static int s_Total; // Static. 크리터 객체의 총 갯수
    Critter(int hunger = 0): m_Hunger(hunger)
    {
        cout << "A critter has been born!" << endl;
        ++s_Total;
    }

    static int GetTotal() // Static 멤버 함수
    {
        return s_Total;
    }

private:
    int m_Hunger;
};

int Critter::s_Total = 0; // 스태틱 데이터 멤버 초기화

int main()
{
    cout << "The total number of critters is: ";
    cout << Critter::s_Total << "\n\n";

    Critter crit1, crit2, crit3;

    cout << "\nThe total number of critters is: ";
    cout << Critter::GetTotal() << "\n";

    return 0;
}
  • 클래스 내 전역변수처럼 사용할 수 있는걸 볼 수 있다.

Critter Caretaker[편집]

  • 간단한 다마고찌를 만들어보자.
/* critter_caretaker.cc */
// Critter Caretaker
// Simulates caring for a virtualpet

#include <iostream>

using namespace std;

class Critter
{
public:
    Critter(int hunger = 0, int boredom = 0);
    void Talk();
    void Eat(int food = 4);
    void Play(int fun = 4);

private:
    int m_Hunger;
    int m_Boredom;

    int GetMood() const;
    void PassTime(int time = 1);
};

Critter::Critter(int hunger, int boredom): m_Hunger(hunger), m_Boredom(boredom)
{}

inline int Critter::GetMood() const
{
    return (m_Hunger + m_Boredom);
}

void Critter::PassTime(int time)
{
    m_Hunger += time;
    m_Boredom += time;
}

void Critter::Talk()
{
    coud << "I'm a critter and I feel ";
    int mood = GetMood();
    if(mood > 15)
        cout << "mad.\n";
    else if(mood > 10)
        cout << "frustrated.\n";
    else if(mood > 5)
        cout << "okay.\n";
    else
        cout << "happy.\n";
    PassTime();
}

void Critter::Eat(int food)
{
    cout << "Brruppp.\n";
    m_Hunger -= food;
    if(m_Hunger < 0)
        m_Hunger = 0;
    PassTime();
}

void Critter::Play(int fun)
{
    cout << "Wheee!\n";
    m_Boredom -= fun;
    if(m_Boredom < 0)
        m_Boredom = 0;
    Passtime();
}

int main()
{
    Critter crit;
    crit.Talk();

    int choice;
    do {
        cout << "\nCritter Caretaker\n\n";
        cout << "0 - Quit\n";
        cout << "1 - Listen to your critter\n";
        cout << "2 - Feed your critter\n";
        cout << "3 - Play with your critter\n\n";

        cout << "Choice: ";
        cin >> choice;

        switch(choice) {
        case 0:
            cout << "Good-bye.\n";
        break;
        case 1:
            crit.Talk();
            break;
        case 2:
            crit.Eat();
            break;
        case 3:
            crit.Play();
            break;
        default:
            cout << "\nSorry, but " << choice << " isn't a valid choice.\n";
        }
    } while(choice != 0);

    return 0;
}
  • 다마고찌같은 게임들은 거의 이런식이다.

Critter Farm[편집]

  • 좀 더 키워보자.
/* critter_farm.cc */
// Critter Farm
// Demonstrates object containment

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Critter
{
public:
    Critter(const string& name = ""): m_Name(name) {}
    string GetName() const { return m_Name; }
private:
    string m_Name;
};

class Farm
{
public:
    Farm(int spaces = 1) { m_Critters.reserve(spaces); }
    void Add(const Critter& aCritter) { m_Critters.push_back(aCritter); }
    void RollCall() const
    {
        for(vector<Critter>::const_iterator iter = m_Critters.begin(); iter != m_Critters.end(); ++iter)
            cout << iter->GetName() << " here.\n";
    }
private:
    vector<Critter> m_Critters;
};

int main()
{
    Critter crit("Poochie");
    cout << "My critter's name is " << crit.GetName() << endl;

    cout << "\nCreating critter farm.\n";
    Farm myFarm(3);

    cout << "\nAdding three critters to the farm.\n";
    myFarm.Add(Critter("Moe"));
    myFarm.Add(Critter("Larry"));
    myFarm.Add(Critter("Curly"));

    cout << "\nCalling Roll...\n";
    myFarm.RollCall();

    return 0;
}
  • 벡터를 쓰니 직관적이다.

Friend Critter[편집]

  • Friend Class를 알아보기 위해 프로그램을 하나 작성해보자.
/* friend_critter.cc */
// Friend Critter
// Demonstrates friend functions and operator overloading

#include <iostream>
#include <string>

using namespace std;

class Critter
{
    // 전역함수는 Critter의 friend class
    friend void Peek(const Critter& aCritter);
    friend void ostream& operator<<(ostream& os, const Critter& aCritter);

public:
    Critter(const string& name = ""): m_name(name) {}

private:
    string m_Name;
};

void Peek(const Critter& aCritter);
ostream& operator<<(ostream& os, const Critter& aCritter);

int main()
{
    Critter crit("Pochie");

    cout << "Calling Peek() to access crit's private data member, m_Name: \n";
    Peek(crit);

    cout << "\nSending crit object to cout with the << operator:\n";
    cout << crit;

    return 0;
}

// 전역 friend 함수는 Critter object의 멤버를 직접 참조할 수 있다.
void Peek(const Critter& aCritter)
{
    cout << aCritter.m_Name << endl;
}

// 전역 friend 함수는 Critter object의 멤버를 직접 참조할 수 있다.
// << 연산자로 cout에 Critter object의 내용을 전달할 수 있다.
ostream& operator << (ostream& os, const Critter& aCritter)
{
    os << "Critter Object - ";
    os << "m_Name: " << aCritter.m_Name;
    return os;
}
  • 점점 고급 기법을 사용할수록 이해하기 힘들다.

Heap[편집]

  • 동적 할당에 대해 알아보자.
/* heap.cc */
// Heap
// Demonstrates dynamically allocating memory

#include <iostream>

using namespace std;

int* intOnHeap(); // int형 변수를 힙에 올려 반환
void leak1(); // 메모리 누수를 만든다.
void leak2(); // 다른 메모리 누수를 만든다.

int main()
{
    int* pHeap = new int;
    *pHeap = 10;
    cout << "*pHeap: " << *pHeap << "\n\n";

    int* pHeap2 = intOnHeap();
    cout << "*pHeap2: " << *pHeap2 << "\n\n";

    cout << "Freeing memory pointed to by pHeap.\n\n";
    delete pHeap;

    cout << "Freeing memory pointed to by pHeap2.\n\n";
    delete pHeap;

    // 애매한 포인터를 지운다.
    pHeap = 0;
    pHeap2 = 0;

    return 0;
}

int* intOnHeap()
{
    int* pTemp = new int(20);
    return pTemp;
}

void leak1()
{
    int* drip1 = new int(30);
}

void leak2()
{
    int* drip2 = new int(50);
    drip2 = new int(100);
    delete drip2;
}
  • 바로 이게 c 계열이 좆같다고힘들다고 하는 메모리관리다.
  • 왜냐하면 메모리 누수 죽어라 많이 일어나거든.

Heap Data Member[편집]

  • 멤버를 동적할당해보자.
/* heap_data_member.cc */
// Heap Data Member
// Demonstrates an object with a dynamically allocated data member

#include <iostream>
#include <string>

using namespace std;

class Critter
{
public:
    Critter(const string& name = "")
    {
        cout << "Constructor called\n";
        m_pName = new string(name);
    }

    ~Critter() // 소멸자
    {
        cout << "Destructor called\n";
        delete m_pName;
    }

    Critter(const Critter& c) // 복사 생성자
    {
        cout << "Copy Constructor called\n";
        m_pName = new string;
        *m_pName = c.GetName();
    }

    Critter& operator=(const Critter& c) // 연산자 지정 오버로드
    {
        cout << " Overloaded Assignment Operator called\n";

        if(this == &c)
        {
            return *this;
        } else {
            *m_pName = c.GetName();
            return *this;
        }
    }

    string GetName() const { return *m_pName; }
    void SetName(const string& name = "") { *m_pName = name; }
    void SayHi() const { cout << "Hi, my name is " << GetName() << "\n"; }

private:
    string* m_pName;
};

void testDestructor();
void testCopyConstructor(Critter copy);
void testAssignmentOp();

int main()
{
    testDestructor();
    cout << endl;

    Critter crit("Poochie");
    crit.SayHi();
    testCopyConstructor(crit);
    cout << endl;

    testAssignmentOp();

    return 0;
}

void testDestructor()
{
    Critter crit("Rover");
    crit.SayHi();
}

// 값으로 받은 object를 복사 생성자로 invoke
void testCopyConstructor(Critter copy)
{
    copy.SayHi();
}

void testAssignmentOp()
{
    Critter crit1("crit1");
    Critter crit2("crit2");
    crit1 = crit2;
    crit1.SayHi();
    crit2.SayHi();

    cout << "Setting name of crit1 back to 'crit1'\n";
    crit1.SetName("crit1");
    crit1.SayHi();
    crit2.SayHi();

    Critter crit("crit");
    crit = crit;
}
  • 더럽게 짜증나는거 다 안다.왜냐하면 나도 쓰면서 짜증났거든

Game Lobby[편집]

  • 온라인 게임에서 대기실같은게 있을 수 있다.
  • Starcraft같은거 해봤으면 다들 알거임.
  • 간략하게 기반을 잡아보자.
/* game_lobby.cc */
// Game Lobby
// Simulates a game lobby where players wait

#include <iostream>
#include <string>

using namespace std;

class Player
{
public:
    Player(const string& name = ""): m_Name(name), m_pNext(0) {}
    string GetName() const { return m_Name; }
    Player* GetNext() const { return m_pNext; }
    void SetNext(Player* next) { m_pNext = next; }
private:
    string m_Name;
    Player* m_pNext; // 리스트중에 다음 플레이어 포인팅
};

class Lobby
{
    friend ostream& operator << (ostream& os, const Lobby& aLobby);
public:
    Lobby(): m_pHead() {}
    ~Lobby() { Clear(); }
    void AddPlayer();
    void RemovePlayer();
    void Clear();
private:
    Player* m_pHead;
};

void Lobby::AddPlayer()
{
    // 플레이어 노드 생성
    cout << "Please enter the name of the new player: ";
    string name;
    cin >> name;
    Player* pNewPlayer = new Player(name);

    // 리스트가 비었으면 새 플레이어를 헤드로 설정
    if(m_pHead == 0)
    {
        m_pHead = pNewPlayer;
    }

    // 그게 아니면 맨 끝에 붙임
    else
    {
        Player* pIter = m_pHead;
        while(pIter->GetNext() != 0)
        {
            pIter = pIter->GetNext();
        }
        pIter->SetNext(pNewPlayer);
    }
}

void Lobby::RemovePlayer()
{
    if(m_pHead == 0)
    {
        cout << "The game lobby is empty. No one to remove!\n";
    } else {
        Player* pTemp = m_pHead;
        m_pHead = m_pHead->GetNext();
        delete pTemp;
    }
}

void Lobby::Clear()
{
    while(m_pHead != 0)
    {
        RemovePlayer();
    }
}

ostream& operator << (ostream& os, const Lobby& aLobby)
{
    Player* pIter = aLobby.m_pHead;

    os << "\nHere's who's in the game lobby:\n";
    if(pIter == 0)
    {
        os << "The lobby is empty.\n";
    } else {
        while(pIter != 0)
        {
            os << pIter->GetName() << endl;
            pIter = pIter->GetNext();
        }
    }

    return os;
}

int main()
{
    Lobby myLobby;
    int choice;

    do {
        cout << myLobby;
        cout << "\nGAME LOBBY\n";
        cout << "0 - Exit the program.\n";
        cout << "1 - Add a player to the lobby.\n";
        cout << "2 - Remove a player from the lobby.\n";
        cout << "3 - Clear the lobby.\n";
        cout << endl << "Enter choice: ";
        cin >> choice;

        switch(choice)
        {
            case 0: cout << "Good-bye.\n"; break;
            case 1: myLobby.AddPlayer(); break;
            case 2: myLobby.RemovePlayer(); break;
            case 3: myLobby.Clear(); break;
            default: cout << "That was not a valid choice.\n";
        }
    } while(choice != 0);

    return 0;
}
  • 이런식으로 좀 신경써놓으면 나중에 기능 추가할때도 편하다.

Simple Boss[편집]

  • 상속에 대해 알아보기 위한 프로그램을 하나 만들어보자.
/* simple_boss.cc */
// Simple Boss
// Demonstrates inheritance

#include <iostream>
using namespace std;

class Enemy
{
public:
    int m_Damage;

    Enemy(): m_Damage(10) { }

    void Attack() const {
        cout << "Attack inflicts " << m_Damage << " damage points!\n";
    }
};

class Boss : public Enemy
{
public:
    int m_DamageMultiplier;

    Boss(): m_DamageMultiplier(3) { }

    void SpecialAttack() const
    {
        cout << "Special Attack inflicts " << (m_DamageMultiplier * m_Damage);
        cout << " damage points!\n";
    }
};

int main()
{
    cout << "Creating an enemy.\n";
    Enemy enemy1;
    enemy1.Attack();

    cout << "\nCreating a boss.\n";
    Boss boss1;
    boss1.Attack();
    boss1.SpecialAttack();

    return 0;
}
  • 좀 더 알아보기 위해 프로그램을 향상시켜보자.
/* simple_boss2.cc */
// simple Boss 2.0
// Demonstrates access control under inheritance

#include <iostream>
using namespace std;

class Enemy
{
public:
    Enemy(): m_Damage(10) { }

    void Attack() const {
        cout << "Attack inflicts " << m_Damage << " damage points!\n";
    }

protected:
    int m_Damage;
};

class Boss : public Enemy
{
public:
    Boss(): m_DamageMultiplier(3) { }

    void SpecialAttack() const {
        cout << "Special Attack inflicts " << (m_DamageMultiplier * m_Damage);
        cout << " damage points!\n";
    }

private:
    int m_DamageMultiplier;
};

int main()
{
    cout << "Creating an enemy.\n";
    Enemy enemy1;
    enemy1.Attack();

    cout << "\nCreating a boss.\n";
    Boss boss1;
    boss1.Attack();
    boss1.SpecialAttack();

    return 0;
}
  • Protected에 대해서 좀 알았을거당
  • Overriding을 봅시다.
/* overriding_boss.cc */
// Overriding Boss
// Demonstrates calling and overriding base member functions

#include <iostream>
using namespace std;

class Enemy
{
public:
    Enemy(int damage = 10): m_Damage(damage) { }
    void Taunt() const {
        cout << "The enemy says he will fight you.\n";
    }

    void Attack() const {
        cout << "Attack! Inflicts " << m_Damage << " damage points.";
    }

private:
    int m_Damage;
};

class Boss : public Enemy
{
public:
    Boss(int damage = 30): Enemy(damage) { } // 기본 생성자에 인자를 주고 호출
    void Taunt() const {
        Enemy::Attack();
        cout << " And laughs heartily at you.\n";
    }
};

int main()
{
    cout << "Creating an enemy.\n";
    Enemy enemy1;
    enemy1.Taunt();
    enemy1.Attack();

    cout << "\n\nCreating a boss.\n";
    Boss boss1;
    boss1.Taunt();
    boss1.Attack();

    return 0;
}
  • 크게 달라보이는게 없당
  • Virtual Member에 대해서 알아보자.
/* virtual_boss.cc */
// Virtual Boss
// Demonstrates virtual functions

#include <iostream>

using namespace std;

class Enemy {
public:
    Enemy(int damage = 10) {
        m_pDamage = new int(damage);
    }

    virtual ~Enemy()
    {
        cout << "m_pDamage deleted\n";
        delete m_pDamage;
    }

    void Taunt() const {
        cout << "The enemy says he will fight you.\n";
    }

    void virtual VTaunt() const {
        cout << "The enemy says he will fight you.\n";
    }

protected:
    int* m_pDamage;
};

class Boss : public Enemy {
public:
    Boss(int multiplier = 3) {
        m_pDamageMultiplier = new int(multiplier);
    }

    virtual ~Boss() {
        cout << "m_pDamageMultiplier deleted\n";
        delete m_pDamageMultiplier;
    }

    void Taunt() const {
        cout << "The boss says he will end your pitiful existence.\n";
    }
    void virtual VTaunt() const {
        cout << "The boss says he will end your pitiful existence.\n";
    }

protected:
    int* m_pDamageMultiplier;
};

int main()
{
    cout << "Pointer to Enemy that points to a Boss object:\n";
    Enemy* pBadGuy = new Boss();
    pBadGuy->Taunt();
    pBadGuy->VTaunt();

    cout << "\nDeleting pointer to Enemy:\n";
    delete pBadGuy;
    pBadGuy = 0;

    return 0;
}
  • 역시 Virtual 멤버도 그다지 달라보이는건 없다.

Abstract Creature[편집]

  • 추상화라고들 이야기하는것에 대해 알아보도록 하자.
/* abstract creature */
// Abstract Creature
// Demonstrates abstract classes

#include <iostream>
using namespace std;

class Creature // Abstract class
{
public:
    Creature(int health = 100): m_Health(health) { }
    virtual void Greet() const = 0; // 순수한 virtual 멤버 함수
    virtual void DisplayHealth() const {
        cout << "Health: " << m_Health << endl;
    }

protected:
    int m_Health;
};

class Orc : public Creature {
public:
    Orc(int health = 120); Creature(health) { }
    virtual void Greet() const {
        cout << "The orc grunts hello.\n";
    }
};

int main()
{
    Creature* pCreature = new Orc();
    pCreature->Greet();
    pCreature->DisplayHealth();

    return 0;
}
  • 계속 진행될수록 메인함수는 작아지는것 같은 느낌인데?

Critter Project[편집]

  • 파일을 나눠보자.
  • 아래는 지금까지처럼의 소스코드
#include <iostream>
using namespace std;

class Critter
{
public:
    void Greet();
};

void Critter::Greet()
{
    cout << "Hi, I'm a critter.\n";
}

int main()
{
    cout << "Instantiating a Critter object.\n\n";

    Critter crit;
    crit.Greet();

    return 0;
}
  • 요걸 세개로 나눌거다.
  1. Header file - Critter class의 정의만.
  2. Implementation file - Critter class의 내용.
  3. Application file - Critter class를 사용하는 main()
  • 아래는 헤더
/* critter.h */
// Header
#ifndef CRITTER_H
#define CRITTER_H

class Critter
{
public:
    void Greet();
};
  • 나중에 엄청 많은 include가 있을 경우 중복 선언을 방지하기 위한 디파인이다.
  • 아래는 구현
/* critter.cc */
// Implementation file

#include <istream>
#include "critter.h"

using namespace std;

void Critter::Greet()
{
    cout << "Hi. I'm a critter.\n";
}
  • 헤더 참조를 하게 했다는것 외에 별다를건 없다.
  • 아래는 어플리케이션
/* critter_app.cc */
// Application file

#include <iostream>
#include "critter.h"

using namespace std;

int main()
{
    cout << "Instantiating a Critter object.\n\n";

    Critter crit;
    crit.Greet();

    return 0;
}
  • 파일 안 나누고 그냥 통짜로 하면 되지 않을까 하는데, c++을 포함한 객체지향 프로그래밍 언어들은 통짜로 짜면 일단 본인이 '내가 뭘 했는지' 까먹게 되고, 유지보수도 잘 안 되는 경향이 있다.
  • 짧은 프로그램에서는 별 차이 안 나지만, 파일별로 기능정리를 한다던가 하면 좀 더 집중할 수 있는 편이다.
  • 그리고, 보통 클래스를 사용하는 경우 협업이라고 하고 혼자 기능 하나를 만든다는 샌드박스 개념으로 협업을 하게 된다.
  • 테스트 역시 클래스 단위로 이루어진다면 어떤 기능이 부족하더라도 dummy를 만들어 돌릴 수 있으니, 평생 혼자여자친구도 없이 모든 프로그래밍을 하지 않을거면 파일 관리를 좀 해보는게 좋다.

Blackjack[편집]

  • 블랙잭은 다음과 같은 순서로 진행된다.
  1. 플레이어와 하우스는 각 두장의 초기 카드를 받는다.
  2. 하우스의 첫카드는 히든
  3. 플레이어와 하우스의 카드를 보여준다.
  4. 플레이어가 카드를 더 받을건지 결정한다.
  5. 하우스가 카드를 깐다
  6. 하우스가 카드를 더 받을건지 결정한다.
  7. 만약 하우스가 버스트하면
    1. 버스트 안한 플레이어 전부 승리
  8. 그렇지 않으려면
    1. 각각 플레이어가
      1. 플레이어가 버스트하지 않았다면
        1. 플레이어가 하우스보다 수가 높으면 플레이어 승리
        2. 그렇지 않고 플레이어보다 하우스가 높으면 플레이어 패배
        3. 숫자가 같으면 플레이어 푸시
  9. 카드 모두 회수
  • 자, 그럼 시작해볼까
// Blackjack
// Plays a simple version of the casino game of blackjac; for 1 - 7 players

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>

using namespace std;

class Card
{
public:
    enum rank { ACE = 1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING };
    enum suit { CLUBS, DIAMONDS, HEARTS, SPADES };

    // << 연산자 오버로딩은 카드 오브젝트를 표준출력으로 내보낸다.
    friend ostream& operator << (ostream& os, const Card& aCard);

    Card(rank r = ACE, suit s = SPADES, bool ifu = true);

    // 카드의 상태 반환, 1 - 11
    int GetValue() const;

    // 카드 뒤집기; 정면이든 아니든 같아야 한다.
    void Flip();

private:
    rank m_Rank;
    suit m_Suit;
    bool m_IsFaceUp;
};

Card::Card(rank r, suit s, bool ifu): m_Rank(r), m_Suit(s), m_IsFaceUp(ifu)
{ }

int Card::GetValue() const {
    // card가 뒤집혀 있으면 0
    int value = 0;
    if(m_IsFaceUp)
    {
        // 카드의 내용이 value
        value = m_Rank;
        // value가 10보다 클 수 없음
        if(value > 10)
            value = 10;
    }
    return value;
}

void Card::Flip()
{
    m_IsFaceUp = !(m_IsFaceUp);
}

class Hand
{
public:
    Hand();

    virtual ~Hand();

    // 카드 추가
    void Add(Card* pCard);

    // 카드 회수
    void Clear();

    // 카드의 값을 구한다. ace는 1이나 11이 될 수 있는데 그걸 판단해줘야 한다.
    int GetTotal() const;

protected:
    vector<Card*> m_Cards;
};

Hand::Hand()
{
    m_Cards.reserve(7);
}

Hand::~Hand() // 클래스 바깥에서 쓸땐 virtual을 빼야함
{
    Clear();
}

void Hand::Add(Card* pCard)
{
    m_Cards.push_back(pCard);
}

void Hand::Clear()
{
    // 처음부터 끝까지 반복하면서 벡터의 내용을 지운다. 힙의 메모리를 전부 반환한다.
    vector<Card*>::iterator iter = m_Cards.begin();
    for(iter = m_Cards.begin(); iter != m_Cards.end(); ++iter)
    {
        delete *iter;
        *iter = 0;
    }
    // 벡터 포인터도 클리어한다.
    m_Cards.clear();
}

int Hand::GetTotal() const {
    // 카드가 없으면 0 반환
    if(m_Cards.empty())
        return 0;

    // 첫카드가 0이면 카드는 뒤집힌 상태이므로 0 반환
    if(m_Cards[0]->GetValue() == 0)
        return 0;

    // 카드 추가, 각 ace는 1로 취급
    int total = 0;
    vector<Card*>::const_iterator iter;
    for(iter = m_Cards.begin(); iter !=m_Cards.end(); ++iter)
        total += (*iter)->GetValue();

    // 만약 카드에 ace가 포함돼 있으면 ace를 결정
    bool containsAce = false;
    for(iter = m_Cards.begin(); iter != m_Cards.end(); ++iter)
        if((*iter)->GetValue() == Card::ACE)
            containsAce = true;

    // 만약 ace가 있고 토탈이 10보다 작으면 ace를 11로
    if(containsAce && total <= 11)
    // 전에 ace를 1 추가했으니, 10만 더 추가하면 된다.
    total += 10;

    return total;
}

class GenericPlayer : public Hand {
    friend ostream& operator << (ostream& os, const GenericPlayer& aGenericPlayer);
public:
    GenericPlayer(const string& name = "");

    virtual ~GenericPlayer();

    // 플레이어가 힛을 하는지 나타내는 값
    virtual bool IsHitting() const = 0;

    // 플레이어가 버스트했는지 나타내는 값 - 버스트는 카드의 총합이 21이 넘는 경우.
    bool IsBusted() const;

    // 버스트했다는걸 표시해주는 함수
    void Bust() const;

protected:
    string m_Name;
};

GenericPlayer::GenericPlayer(const string& name) : m_Name(name)
{ }

GenericPlayer::~GenericPlayer()
{ }

bool GenericPlayer::IsBusted() const
{
    return (GetTotal() > 21);
}

void GenericPlayer::Bust() const
{
    cout << m_Name << " busts.\n";
}

class Player : public GenericPlayer
{
public:
    Player(const string& name = "");

    virtual ~Player();

    // 플레이어가 힛할지 안할건지 리턴
    virtual bool IsHitting() const;

    // 플레이어가 이겼음을 표시
    void Win() const;

    // 플레이어가 졌음을 표시
    void Lose() const;

    // 플레이어 푸시를 표시
    void Push() const;
};

Player::Player(const string& name) : GenericPlayer(name)
{ }

Player::~Player()
{ }

bool Player::IsHitting() const
{
    cout << m_Name << ", do you want a hit? (Y/N): ";
    char response;
    cin >> response;
    return (response == 'y' || response == 'Y');
}

void Player::Win() const {
    cout << m_Name << " wins.\n";
}

void Player::Lose() const {
    cout << m_Name << " loses.\n";
}

void Player::Push() const {
    cout << m_Name << " pushes.\n";
}

class House : public GenericPlayer
{
public:
    House(const string& name = "House");

    virtual ~House();

    // 하우스가 힛하는걸 표현 - 카드 토탈이 16이거나 작으면 무조건 힛
    virtual bool IsHitting() const;

    // 첫장 뒤집기
    void FlipFirstCard();
};

House::House(const string& name) : GenericPlayer(name)
{ }

House::~House()
{ }

bool House::IsHitting() const {
    return (GetTotal() <= 16);
}

void House::FlipFirstCard()
{
    if(!(m_Cards.empty()))
        m_Cards[0]->Flip();
    else cout << "No card to flip!\n";
}

class Deck : public Hand
{
public:
    Deck();
    virtual ~Deck();

    // 52장 카드로 표준 덱을 만듦
    void Populate();

    // 카드 섞기
    void Shuffle();

    // 카드 딜링
    void Deal(Hand& aHand);

    // 추가 카드를 일반 플레이어에게 딜링
    void AdditionalCards(GenericPlayer& aGenericPlayer);
};

Deck::Deck() {
    m_Cards.reserve(52);
    Populate();
}

Deck::~Deck() { }

void Deck::Populate() {
    Clear();
    // 스탠다드 덱을 만듦
    for(int s = Card::CLUBS; s <= Card::SPADES; ++s)
        for(int r = Card::ACE; r < Card::KING; ++r)
            Add(new Card(static_cast<Card::rank>(r), static_cast<Card::suit>(s)));
}

void Deck::Shuffle() {
    random_shuffle(m_Cards.begin(), m_Cards.end());
}

void Deck::Deal(Hand& aHand) {
    if(!m_Cards.empty()) {
        aHand.Add(m_Cards.back());
        m_Cards.pop_back();
    } else {
        cout << "Out of cards. Unable to deal.";
    }
}

void Deck::AdditionalCards(GenericPlayer& aGenericPlayer)
{
    cout << endl;
    // 플레이어가 버스트하지 않고 힛을 하면 카드를 딜링한다.
    while(!(aGenericPlayer.IsBusted()) && aGenericPlayer.IsHitting()) {
        Deal(aGenericPlayer);
        cout << aGenericPlayer << endl;

        if(aGenericPlayer.IsBusted())
            aGenericPlayer.Bust();
    }
}

class Game
{
public:
    Game(const vector<string>& names);

    ~Game();

    // 게임 플레이!
    void Play();

private:
    Deck m_Deck;
    House m_House;
    vector<Player> m_Players;
};

Game::Game(const vector<string>& names)
{
    // 플레이어 이름으로 벡터를 만든다.
    vector<string>::const_iterator pName;
    for(pName = names.begin(); pName != names.end(); ++pName)
        m_Players.push_back(Player(*pName));

    srand(time(0));
    m_Deck.Populate();
    m_Deck.Shuffle();
}

Game::~Game() { }

void Game::Play() {
    // 초기카드 2장을 모두에게 딜링
    vector<Player>::iterator pPlayer;
    for(int i = 0; i < 2; ++i)
    {
        for(pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer)
            m_Deck.Deal(*pPlayer);
        m_Deck.Deal(m_House);
    }

    // 하우스의 첫 카드는 히든
    m_House.FlipFirstCard();

    // 모두의 카드를 표시
    for (pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer)
        cout << *pPlayer << endl;
    cout << m_House << endl;

    // 추가카드를 플레이어들에게 딜링
        for(pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer)
        m_Deck.AdditionalCards(*pPlayer);

    // 하우스 히든 공개
    m_House.FlipFirstCard();
    cout << endl << m_House;

    // 하우스 카드 딜링
    m_Deck.AdditionalCards(m_House);

    if(m_House.IsBusted())
    {
        // 버스트 안한 모든 플레이어 승리
        for(pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer)
            if(!(pPlayer->IsBusted()))
                pPlayer->Win();
    } else {
        // 각각의 플레이어가 하우스를 이겼는지 확인
        for(pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer)
            if(!(pPlayer->IsBusted())) {
                if(pPlayer->GetTotal() > m_House.GetTotal())
                    pPlayer->Win();
                else if(pPlayer->GetTotal() < m_House.GetTotal())
                    pPlayer->Lose();
                else
                    pPlayer->Push();
            }
    }

    // 모든 카드 회수
    for(pPlayer = m_Players.begin(); pPlayer != m_Players.end(); ++pPlayer)
        pPlayer->Clear();
    m_House.Clear();
}

// 함수 프로토타입
ostream& operator << (ostream& os, const Card& aCard);
ostream& operator << (ostream& os, const GenericPlayer& aGenericPlayer);

int main()
{
    cout << "\t\tWelcome to Blackjack!\n\n";

    int numPlayers = 0;
    while(numPlayers < 1 || numPlayers > 7) {
        cout << "How many palyers? (1 - 7): ";
        cin >> numPlayers;
    }

    vector<string> names;
    string name;
    for(int i = 0; i < numPlayers; ++i)
    {
        cout << "Enter player name: ";
        cin >> name;
        names.push_back(name);
    }
    cout << endl;

    // 게임 루프
    Game aGame(names);
    char again = 'y';
    while(again != 'n' && again != 'N') {
        aGame.Play();
        cout << "\nDo you want to play agin? (Y/N): ";
        cin >> again;
    }

    return 0;
}

// 카드 오브젝트에서 << 연산자 오버로드
ostream& operator << (ostream& os, const Card& aCard)
{
    const string RANKS[] = { "0", "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };
    const string SUITS[] = { "c", "d", "h", "s" };

    if(aCard.m_IsFaceUp)
        os << RANKS[aCard.m_Rank] << SUITS[aCard.m_Suit];
    else
        os << "XX";

    return os;
}

// 플레이어 오브젝트에서 << 연산자 오버로드
ostream& operator << (ostream& os, const GenericPlayer& aGenericPlayer)
{
    os << aGenericPlayer.m_Name << ":\t";
    vector<Card*>::const_iterator pCard;
    if(!aGenericPlayer.m_Cards.empty())
    {
        for(pCard = aGenericPlayer.m_Cards.begin(); pCard != aGenericPlayer.m_Cards.end(); ++pCard)
            os << *(*pCard) << "\t";

        if(aGenericPlayer.GetTotal() != 0)
            cout << "(" << aGenericPlayer.GetTotal() << ")";
    } else {
        os << "<empty>";
    }
    return os;
}
  • 블랙잭 정도는 껌인가?

Multiplayer Game Programming[편집]

SDL[편집]

  1. Linux/X11
  2. Windows
  3. Windows CE
  4. Mac OSX
  5. iOS
  6. Android
  • 사용되는 IDE
  1. Code::Blocks
  2. Visual C++
  3. Eclipse
  • 라이센스는 LGPL이다.
  1. 자유롭게 상용프로그램 개발이 가능
  2. 상용으로 개발할 경우 SDL과 게임은 Dynamic Link되어야 함.
  • 일단 간단하게 만들기에 짱좋은 라이브러리

준비[편집]

  • 개발킷을 설치한다(다음은 데비안/우분투 기준)
$ sudo apt-get install libsdl1.2-dev
  • 우분투에서는 우분투소프트웨어센터에서 검색해서 받는게 좋다.
  • 만약 윈도우라면 Visual C++과 MinGW용 라이브러리가 있다.

Hello World[편집]

  • 뭐든 헬로월드부터 찍어봐야지.. 안그래?
/* sdltest.c */
/*
    SDL Test
    Demonstrates SDL being initialized and shut down.
    written by Sayuri L. Kitsune (2012)
*/
 
/* Includes */
#include <SDL.h>
#include <stdio.h>
 
/* Main */
int main(int argn,char **argv)
{
    /* Init */
    if(SDL_Init(SDL_INIT_VIDEO) != 0)
        fprintf(stderr,"Could not initialize SDL: %s\n",SDL_GetError()); /* Error? */
    printf("SDL Initialized\n");
    /* Exit */
    SDL_Quit();
    printf("SDL Shutdown\n");
    /* Done */
    return 0;
}
  • 그럼 하던대로 컴파일을 해볼까!
$ gcc -c sdltest.c
  • 으메, 헤더파일 없다고 나오네
  • 헤더파일은 /usr/include/SDL에 있당
  • 그러니까 이렇게
$ gcc -I"/usr/include/SDL" -c sdltest.c
  • 자, 컴파일은 됐어.
  • 이제 링크!
$ gcc -o sdltest sdltest.o
  • 또 에러네? 젠장
  • 라이브러리 링크해줘야함
$ gcc -o sdltest sdltest.o -lSDL
  • 그냥 한번에 다 할라면
$ gcc -o sdltest sdltest.c -I"/usr/include/SDL" -lSDL
  • 실행해보면 그냥 초기화되고 꺼졌다는 메세지 나와
  • 그럼 성공

SDL_PollEvent[편집]

  • 그래도 화면 나오는게 보고 싶겠지.
  • 화면 초기화하고 어떤 입력을 받는 루틴을 짜보자.
/* demo.c */
/*
    SDL Video Demo
    demonstrates SDL's video working by moving dots around a screen
    written by Sayuri L. Kitsune (2012)
*/
 
/* Includes */
#include <SDL.h>
 
/* Globals */
SDL_Surface *demo_screen;
 
/* Main */
int main(int argn,char **argv)
{
    SDL_Event ev;
    int active;
    /* Initialize SDL */
    if(SDL_Init(SDL_INIT_VIDEO) != 0)
        fprintf(stderr,"Could not initialize SDL: %s\n",SDL_GetError());
    /* Open main window */
    demo_screen = SDL_SetVideoMode(320,240,0,SDL_HWSURFACE|SDL_DOUBLEBUF);
    if(!demo_screen)
        fprintf(stderr,"Could not set video mode: %s\n",SDL_GetError());
    /* Main loop */
    active = 1;
    while(active)
    {
        /* Handle events */
        while(SDL_PollEvent(&ev))
        {
            if(ev.type == SDL_QUIT)
                active = 0; /* End */
        }
    }
    /* Exit */
    SDL_Quit();
    return 0;
}
  • 솔직히 옵션 넣어야 할게 좀 있고 귀찮으니 Makefile도 하나 만들자.
test:
    make build;
    ./demo;
 
build:
    gcc -I"/usr/include/SDL" -c demo.c;
    gcc demo.o -lSDL -o demo;
 
clean:
    -rm demo.o;
    -rm demo;
  • 창 하나가 뜬다.

SDL_app[편집]

  • 간단하게 화면출력하는거 하나 만들어봅시다.
/* sdl_app.c */
#include <SDL/SDL.h>
int main ( int argc, char** argv )
{
  SDL_Init(SDL_INIT_EVERYTHING);
  SDL_Surface* screen = SDL_SetVideoMode(320, 240, 16, SDL_SWSURFACE);
  SDL_Surface* bmp = SDL_LoadPNG("back.png");
  SDL_Rect dstrect; 
  dstrect.x = 0; 
  dstrect.y = 0;
  SDL_BlitSurface(bmp, NULL, screen, &dstrect);
  SDL_Flip(screen);
  SDL_Delay(5000);
  SDL_FreeSurface(bmp);
  SDL_FreeSurface(screen);
  SDL_Quit();
  return 0;
}

다음은 Makefile.sdl_app

test:
    make build;
 
build:
    gcc -I"/usr/include/SDL" -c sdl_app.c;
    gcc demo.o -lSDL -o sdl_app;
 
clean:
    -rm sdl_app.o;
    -rm sdl_app;
  • 아무 그림파일이나 320x240 해상도에 맞춰 bmp로 저장하고 make -f Makefile.sdl_app 이런식으로 하면 되겠다.
  • 아 솔직히 귀찮으면 디렉토리별로 나누면 그게 짱
  • 대충 snail 애니메이션을 해보자.
/* sdl_ani.c */
#include <SDL/SDL.h>
int main ( int argc, char** argv )
{
  SDL_Init(SDL_INIT_EVERYTHING);
  SDL_Surface* screen = SDL_SetVideoMode(480, 272, 16, SDL_SWSURFACE);
  SDL_Surface* bmp = SDL_LoadBMP("character.bmp");
  SDL_Rect dstrect;
  dstrect.y = 100;
  for (int x = 0; x < 480; x++) {
    dstrect.x = x;
    SDL_BlitSurface(bmp, NULL, screen, &dstrect);
    SDL_Flip(screen);
    SDL_Delay(10);
  }
  SDL_FreeSurface(bmp);
  SDL_FreeSurface(screen);
  SDL_Quit();
  return 0;
}
  • 다음은 Makefile.sdl_ani
test:
    make build;
 
build:
    gcc -I"/usr/include/SDL" -c sdl_ani.c;
    gcc demo.o -lSDL -o sdl_ani;
 
clean:
    -rm sdl_ani.o;
    -rm sdl_ani;
  • 대충 100x100짜리 bmp파일을 character.bmp이라고 명명해서 같은 디렉토리에 넣어두고 실행해보자.

videodemo[편집]

  • 점찍기 프로그램이다.
/*
    SDL Video Demo
    demonstrates SDL's video working by moving dots around a screen
    written by Sayuri L. Kitsune (2012)
*/
 
/* Defines */
#define NUM_DOTS 1024
 
/* Includes */
#include <time.h>
#include <SDL.h>
#include <stdlib.h>
 
/* Types */
typedef struct
{
    int red,green; /* The shade of color in red,green. blue is always 0 since we're using it as the background */
    float vx,vy; /* Speed the particle is moving */
    float x,y; /* Current position of particle */
}dot;
 
/* Globals */
SDL_Surface *demo_screen;
float demo_time_measure = 0.0f;
float demo_time_step = 0.0f;
dot demo_dots[NUM_DOTS];
 
/* Returns a random floating point number between 0.0f and 1.0f */
float demo_roll()
{
    float r;
    r = (float)(rand()%RAND_MAX); /* 0 ~ whatever RAND_MAX is */
    r /= (float)(RAND_MAX-1); /* one less than RAND_MAX makes it possible for 1.0f to happen */
    return r;
}
 
/* Initialize dots */
void demo_init()
{
    int i;
    for(i = 0;i < NUM_DOTS;i++)
    {
        demo_dots[i].red = rand()%255;
        demo_dots[i].green = rand()%255;
        demo_dots[i].vx = demo_roll()*16.0f-8.0f;
        demo_dots[i].vy = demo_roll()*16.0f-8.0f;
        demo_dots[i].x = demo_roll()*320.0f;
        demo_dots[i].y = demo_roll()*240.0f;
    }
}
 
/* Handle dots */
void demo_handle()
{
    int i;
    for(i = 0;i < NUM_DOTS;i++)
    {
        /* Move */
        demo_dots[i].x += demo_dots[i].vx*demo_time_step;
        demo_dots[i].y += demo_dots[i].vy*demo_time_step;
        /* Hit walls? */
        if(demo_dots[i].x < 0.0f || demo_dots[i].x >= 320.0f)
        {
            /* Undo move (demo_time_step is still the same value it was before and is valid for the current frame) */
            demo_dots[i].x -= demo_dots[i].vx*demo_time_step;
            /* Reverse */
            demo_dots[i].vx = -demo_dots[i].vx;
        }
        if(demo_dots[i].y < 0.0f || demo_dots[i].y >= 240.0f)
        {
            /* Undo move (demo_time_step is still the same value it was before and is valid for the current frame) */
            demo_dots[i].y -= demo_dots[i].vy*demo_time_step;
            /* Reverse */
            demo_dots[i].vy = -demo_dots[i].vy;
        }
    }
}
 
/* Draw dots */
void demo_draw()
{
    int i,bpp,rank,x,y;
    Uint32 *pixel;
    /* Lock surface */
    SDL_LockSurface(demo_screen);
    rank = demo_screen->pitch/sizeof(Uint32);
    pixel = (Uint32*)demo_screen->pixels;
    /* Draw all dots */
    for(i = 0;i < NUM_DOTS;i++)
    {
        /* Rasterize position as integer */
        x = (int)demo_dots[i].x;
        y = (int)demo_dots[i].y;
        /* Set pixel */
        pixel[x+y*rank] = SDL_MapRGBA(demo_screen->format,demo_dots[i].red,demo_dots[i].green,0,255);
    }
    /* Unlock surface */
    SDL_UnlockSurface(demo_screen);
}
 
/* Convert from timespec to float */
float demo_convert_time(struct timespec *ts)
{
    float accu;
    /* Combine the value into floating number */
    accu = (float)ts->tv_sec; /* Seconds that have gone by */
    accu *= 1000000000.0f; /* One second is 1000x1000x1000 nanoseconds, s -> ms, us, ns */
    accu += (float)ts->tv_nsec; /* Nanoseconds that have gone by */
    /* Bring it back into the millisecond range but keep the nanosecond resolution */
    accu /= 1000000.0f;
    return accu;
}
 
/* Start time */
void demo_start_time()
{
    struct timespec ts;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts);
    demo_time_measure = demo_convert_time(&ts);
}
 
/* End time */
void demo_end_time()
{
    struct timespec ts;
    float delta;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts);
    delta = demo_convert_time(&ts)-demo_time_measure; /* Find the distance in time */
    demo_time_step = delta/(1000.0f/16.0f); /* Weird formula, equals 1.0f at 16 frames a second */
}
 
/* Main */
int main(int argn,char **argv)
{
    SDL_Event ev;
    int active;
    /* Initialize SDL */
    if(SDL_Init(SDL_INIT_VIDEO) != 0)
        fprintf(stderr,"Could not initialize SDL: %s\n",SDL_GetError());
    /* Open main window */
    demo_screen = SDL_SetVideoMode(320,240,0,SDL_HWSURFACE|SDL_DOUBLEBUF);
    if(!demo_screen)
        fprintf(stderr,"Could not set video mode: %s\n",SDL_GetError());
    /* Initialize game */
    demo_init();
    /* Main loop */
    active = 1;
    while(active)
    {
        /* Handle events */
        while(SDL_PollEvent(&ev))
        {
            if(ev.type == SDL_QUIT)
                active = 0; /* End */
        }
        /* Start time */
        demo_start_time();
        /* Handle game */
        demo_handle();
        /* Clear screen */
        SDL_FillRect(demo_screen,NULL,SDL_MapRGBA(demo_screen->format,0,0,255,255));
        /* Draw game */
        demo_draw();
        /* Show screen */
        SDL_Flip(demo_screen);
        /* End time */
        demo_end_time();
    }
    /* Exit */
    SDL_Quit();
    return 0;
}
  • 초당 16프레임으로 랜덤으로 이동하는 1024개의 픽셀을 표현하는걸 만들었다.