cocos2d-x를 한번 사용해보자 

우선 cocos2d-x파일을 설치 및 자동 환경설정을 하기 위해서는 홈페이지에서 zip파일을 다운받은 다음 setup.py를 실행시켜야한다. 이를 위해 python을 설치해주자. 

검색해봤을 때 python 버전은 2버전대를 설치해주자 

이 버전을 설치하는 이유는 cocos2d-console 도구가 Python 2 문법 기반으로 작성되어있기 때문이다.

 

https://www.python.org/downloads/release/python-2718/

 

Python Release Python 2.7.18

The official home of the Python Programming Language

www.python.org

 

이 링크에 접속한 다음 자신의 컴퓨터에 맞는 실행파일을 다운 받아 설치해주면된다. 설치할 때 add to path를 추가해주어야 정상적으로 작동한다.

 

이렇게 설치해준 다음, cocos2d-x 파일을 다운받아주자. cocos2dx는 버전은 3.17.2로 진행하였다. 

https://www.cocos.com/en/cocos2dx-download

 

이렇게 다운 받은 다음 cmd창이나 bash창을 통해 cocos2d-x파일의 압축을 푼 경로로 이동하여 다음 명령어를 입력해주자.

python setup.py

 

이렇게 해주면 입력하라는 창이 나올텐데 이것은 SDK 경로를 입력하는 창으로 당장은 필요하지 않기 때문에 Enter를 눌러 넘어가주자.

 

이렇게 해준다음 cocos 명령어를 통해 프로젝트를 생성하면 된다. 명령어는 위와 동일하게 cmd창이나 bash창에 입력하면 된다. 중요한 점은 이때 프로젝트는 cocos2d-x의 파일을 압축푼 곳에 생성해야 올바르게 작동한다는 점이다. 나는 projects라는 새로운 폴더를 만들고 이곳에 프로젝트를 생성해주었다.

C:\cocos2d-x-3.17.2\projects

cocos new [프로젝트 이름] -p [패키지 이름] -l [언어] -d [경로]

 

이렇게 만들어준 다음 proj.win32 폴더로 가서 sln파일을 열어주고 실행해보았을 때 cocos2d-x 아이콘과 화면이 등장하면 성공이다.

간단한 비행기 슈팅게임을 만들어보자. 

1.움직이기

움직이는 것을 new Input System을 통해 구현해보자.

우선 InputAction에서 Generate C# class를 켜주고 Apply해서 코드로 불러낼 수 있도록 해주자.

 

이렇게 해준다음 Player 클래스를 생성하여 매핑된 Actions가 작동될 때 실행될 함수를 할당해주자.

 

우선 입력을 받아올 때 입력 이벤트의 context를 Vector2로 읽어드려서 어떤 방향에서의 입력인지 알아내고 이를 저장한다. 저장한 값이 0보다 크다면 해당 방향으로 이동을 시작하게 한다. 이때 키 입력이 끝났을 때 다시 입력값을 0으로 초기화 해주어야 정상적으로 작동한다.

 

Player.cs

public class Player : MonoBehaviour
{

	private PlayerInputActions _playerInputAtions;
    
     void Update()
 	{
    
         if (_movementInput.magnitude > 0)
         {
             Vector2 direction = new Vector2(_movementInput.x, _movementInput.y);
             direction.Normalize();
             transform.Translate(direction * _speed * Time.deltaTime);
         }

    
 	}
    
    
     private void PlayerMove(InputAction.CallbackContext context)
     {
         _movementInput = context.ReadValue<Vector2>();
     }
     
       private void PlayerStop(InputAction.CallbackContext context)
      {
          _movementInput = Vector2.zero;
      }
    
	private void OnEnable()
 	{
         _playerInputAtions = new PlayerInputActions();
         _playerInputAtions.Player.Move.performed += PlayerMove;
         _playerInputAtions.Enable();
 	}
}

 

그리고 슈팅게임이기 때문에 경계선 check를 해주어서 만약 viewport 밖으로 나간다면 반대쪽으로 돌아오도록 구현해주자.

void Update()
{
    transform.position = BoundaryCheck(transform.position);
    if (_movementInput.magnitude > 0)
    {
        Vector2 direction = new Vector2(_movementInput.x, _movementInput.y);
        direction.Normalize();
        transform.Translate(direction * _speed * Time.deltaTime);
    }

   
}

public Vector2 BoundaryCheck(Vector2 position)
{
    Vector2 newposition = position;
    Vector2 viewPort = _mainCamera.WorldToViewportPoint(position);

    if (viewPort.x < 0)
    {
        newposition.x = _mainCamera.ViewportToWorldPoint(new Vector2(1, 0)).x;
    }
    else if (viewPort.x > 1)
    {
        newposition.x = _mainCamera.ViewportToWorldPoint(new Vector2(0, 0)).x;

    }

    newposition.y = Mathf.Clamp(newposition.y, _mainCamera.ViewportToWorldPoint(new Vector2(0, 0)).y, _mainCamera.ViewportToWorldPoint(new Vector2(0, 1)).y);

    return newposition;
}

 

5줄의 문자들을 입력받아야하는데 이때 한줄에 문자는 15개가 최대로 올 수 있다. 빈칸없이 연속으로 주어져서 어떻게 풀어야할지 고민을 했는데 생각해보면 문자열로 배열처럼 접근할 수 있기 때문에 한줄씩 받은 다음 접근을 세로로 하면 된다.

 

정답코드

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

using namespace std;

int main()
{
    vector<string> v(5, ""); // 5줄의 문자열 벡터 생성

    // 입력 받기
    for (int i = 0; i < 5; i++)
    {
        getline(cin, v[i]); // 한 줄씩 입력받아 벡터에 저장
    }

    // 세로로 읽어서 출력
    for (int i = 0; i < 15; i++) // 최대 15개의 열
    {
        for (int j = 0; j < 5; j++) // 5개의 행
        {
            if (i < v[j].size()) // 현재 행의 i번째 문자가 존재하면 출력
            {
                cout << v[j][i];
            }
        }
    }

    return 0;
}

단어를 입력으로 받았을 때, 몇개의 단어가 그룹단어인지 개수를 출력해주면 된다.

이때 그룹단어는 같은 단어가 연속해서 나타나는 경우를 의미한다.

소문자의 개수만큼 bool vector를 선언하고 단어의 알파벳을 하나씩 순회하는데 이전에 나온 알파벳과 비교하여 다를 

경우 방문했는지 체크하고 방문했다면 false를 반환해주고 다 체크했을 때 이상이 없으면 true를 반환해주는 함수를 통해 그룹함수인지를 체크하자.

 

정답코드

#include <iostream>
#include <vector>

using namespace std;

bool isGroup(string s);

int main()
{
	int n;
	cin >> n;

	int count = 0;

	for (int i = 0;i < n;i++)
	{
		string s;
		cin >> s;
		if (isGroup(s))
		{
			count++;
		}
	}

	cout << count;
}

bool isGroup(string s)
{
	vector<bool> visited(26, false);

	char pre_c = ' ';

	for (char c : s)
	{
		//만약 전에 나왔던 알파벳과 다르다면
		if (c != pre_c)
		{
			//방문하지 않았던 거라면
			if (!visited[c - 'a'])
			{
				visited[c - 'a'] = true;
				pre_c = c;
				continue;
			}
			else  //방문했었던거라면 그룹단어가 아님
			{
				return false;
			}
		}
	}

	return true;
}

 

문자를 입력받고 가장 많이 사용된 알파벳을 출력해주는데 만약 가장 많이 사용된 알파벳이 여러개 있다면 ?를 출력해주면 된다.

 

처음에 map을 사용하여 풀어서 정답이었지만 다음과 같은 문제점이 있어서 코드를 수정해보았다.

 

  • map<char, int> 대신 array 사용
    • map은 내부적으로 Red-Black Tree 구조를 사용하여 삽입과 조회가 O(log N) 소요됨.
    • 하지만 알파벳 개수는 26개로 고정되어 있으므로, 배열(array<int, 26>)을 사용하면 O(1)으로 빠르게 접근 가능.
  • tolower() 변환 시 불필요한 중복 연산 제거
    • 현재 tolower()를 여러 번 호출하고 있지만, 한 번 변환한 후 바로 인덱스로 사용하면 중복 연산 감소.
  • 최댓값 찾기 및 중복 체크를 하나의 반복문으로 수행
    • 현재는 두 개의 반복문을 사용하여 최댓값과 중복 여부를 검사 (O(N) + O(26))
    • 한 번의 반복문(O(26))으로 최댓값과 중복 여부를 처리하여 최적화 가능

 

 

정답코드(map사용)

#include <iostream>
#include <cctype>
#include <map>

using namespace std;

map<char, int> m;
int main()
{
	string s;
	cin >> s;
	
	for (int i = 0;i < s.length();i++)
	{
		m[tolower(s[i])]++;
	}
	
	int max_value = m[s[0]];
	char max_char = s[0];
	int cnt = 0;

	for (const auto& pair : m) {
		if (max_value < pair.second)
		{
			max_value = pair.second;
			max_char = pair.first;
		}
	}

	for (const auto& pair : m) {
		if (max_value == pair.second)
		{
			cnt++;
		}
	}

	if (cnt > 1)
	{
		cout << "?";
	}
	else
	{
		cout << char(toupper(max_char));
	}
}

 

정답코드(효율적, Array사용)

#include <iostream>
#include <array>

using namespace std;

int main()
{
    string s;
    cin >> s;

    array<int, 26> freq = { 0 }; // 알파벳 개수(26) 만큼 배열 생성 및 초기화

    // 문자 개수 세기
    for (char c : s)
    {
        freq[tolower(c) - 'a']++;
    }

    // 최댓값 찾기 & 중복 체크
    int max_value = 0, max_index = -1;
    bool is_duplicate = false;

    for (int i = 0; i < 26; i++)
    {
        if (freq[i] > max_value)
        {
            max_value = freq[i];
            max_index = i;
            is_duplicate = false; // 새로운 최댓값이 나오면 중복 여부 초기화
        }
        else if (freq[i] == max_value)
        {
            is_duplicate = true;
        }
    }

    // 출력
    if (is_duplicate)
        cout << "?";
    else
        cout << char(max_index + 'A'); // 대문자로 변환

    return 0;
}

 

100줄을 입력받아서 그대로 출력해줘야하기 때문에 ostringstream을 사용해보았다. getline을 통해 한줄씩 ostringstream에 추가하고 공백을 입력받으면 마지막에 한번에 출력해주는 방식을 사용하였다.

 

정답코드

#include <iostream>
#include <sstream>


using namespace std;


int main()
{
	ostringstream output;

	while (1)
	{
		string s;
		getline(cin, s);
		if (s.empty()) break;

		output << s << "\n";
	}

	cout << output.str();

	return 0;
}

 

문제의 규칙성을 찾아야한다. 일단 알파벳이 아닌 1까지 가는 시간이 2초가 걸리기 때문에 A부터 C까지는 3초가 걸리고 D~F까지는 4초가 걸린다. 이때 4개의 알파벳이 있는 수도 있기 때문에 예외처리를 해주어야 한다. 

 

 

정답코드

#include <iostream>

using namespace std;


int main()
{
	int sum = 0;
	string s;
	cin >> s;

	for (char c : s)
	{
		//기본이 2초 알파벳 3개가 지날 때마다 1초씩 증가
		sum += ((int)c-65) / 3 + 3;

		if (c == 'S' || c == 'V' || c == 'Y' || c == 'Z') sum--;
	}
	
	cout << sum;

	return 0;
}

1. istringstream (입력 스트림, string → cin처럼 사용)

문자열을 입력 스트림으로 변환하여 cin처럼 사용할 수 있음.
✔ 공백을 기준으로 문자열을 분리하여 읽을 때 유용함.

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main() {
    string input = "123 456 789";
    istringstream iss(input);  // 문자열을 입력 스트림으로 변환

    int num;
    while (iss >> num) {  // 공백 기준으로 숫자 추출
        cout << num << endl;
    }

    return 0;
}

2. ostringstream (출력 스트림, cout처럼 string에 출력)

문자열을 생성 및 조합할 때 사용.
✔ cout처럼 데이터를 추가할 수 있음.
✔ += 연산자보다 빠르게 문자열을 결합하는 방법 중 하나.

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main() {
    ostringstream oss;  // 출력 스트림 생성

    oss << "Hello, " << "World! " << 2024;  // 여러 개의 데이터를 추가

    string result = oss.str();  // 최종 문자열 변환
    cout << result << endl;  // 출력

    return 0;
}

 

3. stringstream (입출력 스트림, istringstream + ostringstream)

istringstream과 ostringstream을 동시에 사용할 수 있음.
✔ 문자열을 읽고(>>) 쓰기(<<) 모두 가능.
한 번에 문자열을 처리할 때 유용.

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main() {
    stringstream ss;  // 문자열 스트림 생성

    ss << "100 200 300";  // 문자열 입력

    int num;
    while (ss >> num) {  // 문자열에서 숫자 추출
        cout << "읽은 숫자: " << num << endl;
    }

    ss.clear();  // 스트림 상태 초기화
    ss << "새로운 데이터 추가";  // 새로운 문자열 입력

    cout << "최종 문자열: " << ss.str() << endl;  // 전체 문자열 출력

    return 0;
}

 

📌 istringstream vs ostringstream vs stringstream 차이점

스트림 종류설명주요 기능

istringstream 문자열 → 입력 스트림(cin처럼 사용) >> 연산자로 값 추출
ostringstream 출력 스트림 → 문자열(cout처럼 사용) << 연산자로 문자열 결합
stringstream 입출력 모두 가능 (istringstream + ostringstream) >>와 << 모두 사용 가능

 

 

 

3.map / unordered_map 초기화 방식

,를 사용하여 초기화 가능

map보다는 unordered_map을 사용하는게 조회가 빠르다.

unordered_map<string, double> grade_map = {
   {"A+", 4.5}, {"A0", 4.0}, {"B+", 3.5}, {"B0", 3.0},
   {"C+", 2.5}, {"C0", 2.0}, {"D+", 1.5}, {"D0", 1.0}, {"F", 0.0}
};

 

 

4.#define보다는 const 

#define으로 상수를 정의하면 컴파일에서는 이 값을 상수로 만들어서 실행시키기 떄문에 오류가 발생했을 떄 디버깅에서 오류를 찾기 어려울 수도 있기 때문에 상수값을 정의할 때는 #define 보다는 const를 사용하는 것이 좋다.

또한 매크로를 사용하여 정의하게 되면 이 상수값이 등장하는 만큼 이 사본이 등장하게 되지만 const를 사용하면 사본은 단 하나만 존재하게 된다.

 

테스트 케이스 마다 각 문자를 R번 반복한다. 이때 outputstream을 사용하여 문자열 연결 성능 최적화하고 string 함수를 통해 해당 문자를 반복해서 들어가도록 해주자.

 

정답코드

#include <iostream>
#include <string>
#include <sstream>  

using namespace std;

int main()
{
    int t;
    cin >> t;

    

    while (t--)
    {
        ostringstream output; // 전체 출력을 저장할 스트림
        int r;
        string s;
        cin >> r >> s;

        for (char c : s)  // `s[j]` 대신 range-based for loop 사용
        {
            output << string(r, c);  // 문자를 r번 반복하여 추가
        }
        cout << output.str()<<"\n";  // 최종 출력
       
    }

    

    return 0;
}

'코딩테스트 > 백준' 카테고리의 다른 글

[백준][C++]11718번. 그대로 출력  (0) 2025.03.06
[백준][C++]5622번. 다이얼  (0) 2025.03.06
[백준][C++]1546번. 평균  (0) 2025.03.06
[백준][C++]10811번. 바구니 뒤집기  (0) 2025.03.06
[백준][C++]2562번. 최댓값  (0) 2025.03.06

 

주어진 점수를 배열에 입력받고 최대값을 max_element를 통해 구하고 이를 통해 새로운 점수의 합을 계산

평균을 구해주면 된다.

이때 나눗셈을 할때 static_cast를 통해 double로 캐스팅을 해주어야 값의 손실이 없다. 그리고 소숫점 6자리까지 출력하게 해주는 코드는 다음과 같다.

  cout << fixed;
  cout.precision(6); // 소수점 6자리까지 출력

 

 

정답코드

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

using namespace std;


int main()
{
    int n;
    cin >> n;
    vector<int> v(n);
    for (int i = 0;i<n;i++)
    {
        cin >> v[i];
    }

    int m = *max_element(v.begin(), v.end());
    double sum = 0.0;
    for (int i:v)
    {
        sum += (static_cast<double>(i) / m * 100);
    }

    cout << fixed;
    cout.precision(6); // 소수점 6자리까지 출력
    cout << sum / n << "\n"; // 평균 출력

    return 0;
}

+ Recent posts