TIL

TIL - 카드 뭉치 문제 풀이와 UI 구조 개선 방향

think95592 2026. 7. 2. 20:52

1. 프로그래머스 「카드 뭉치」

문제 핵심

두 개의 카드 뭉치 cards1, cards2가 있고, 각 카드 뭉치의 순서는 바꿀 수 없다.

목표 단어 배열 goal을 만들기 위해서는 매번 두 카드 뭉치 중 하나의 맨 앞 카드만 사용할 수 있다.

즉, 중요한 규칙은 다음과 같다.

  • 카드 뭉치의 순서는 바꿀 수 없다.
  • 카드를 건너뛸 수 없다.
  • 사용한 카드는 다시 사용할 수 없다.
  • goal의 단어를 앞에서부터 하나씩 만들 수 있는지 확인한다.

풀이 아이디어

각 카드 뭉치에서 현재 확인해야 하는 위치를 인덱스로 관리한다.

int idx1 = 0;
int idx2 = 0;

goal을 앞에서부터 하나씩 확인하면서,

  1. 현재 단어가 cards1[idx1]와 같으면 idx1++
  2. 아니면 cards2[idx2]와 같은지 확인하고 같으면 idx2++
  3. 둘 다 아니면 만들 수 없으므로 "No" 반환

코드

#include <string>
#include <vector>

using namespace std;

string solution(vector<string> cards1, vector<string> cards2, vector<string> goal) {
    int idx1 = 0;
    int idx2 = 0;

    for (int i = 0; i < goal.size(); i++)
    {
        if (idx1 < cards1.size() && cards1[idx1] == goal[i])
        {
            idx1++;
        }
        else if (idx2 < cards2.size() && cards2[idx2] == goal[i])
        {
            idx2++;
        }
        else
        {
            return "No";
        }
    }

    return "Yes";
}

배운 점

1. if - else if - else는 하나만 실행된다.

if 조건이 참이면 그 블록만 실행되고, 뒤의 else if, else는 실행되지 않는다.

이번 문제에서는 하나의 단어를 cards1 또는 cards2 중 하나에서만 가져오면 되기 때문에 if - else if - else 구조가 적합했다.


2. return은 함수 전체를 종료한다.

반복문 안에서 return "No";가 실행되면 for문만 끝나는 것이 아니라 solution 함수 전체가 종료된다.

따라서 더 이상 확인할 필요가 없는 실패 상황에서는 return을 바로 사용하는 것이 좋다.


3. 배열을 직접 삭제하지 않아도 된다.

카드를 사용했다고 해서 실제로 배열에서 지울 필요는 없다.

대신 idx1, idx2를 증가시키면 다음에 사용할 카드 위치를 가리킬 수 있다.

즉, 인덱스를 이동시키는 것만으로도 “카드를 한 장 사용했다”는 상태를 표현할 수 있다.


2. UI 구조 개선 - 직접 참조에서 MVVM 방향으로 변경

기존 방식

처음에는 위젯이나 액터가 서로를 직접 참조하는 방식으로 UI를 구성했다.

예를 들어,

  • 버튼 클릭
  • 특정 액터나 저장소 직접 참조
  • 데이터를 가져와서 UI 텍스트 직접 변경

같은 흐름이었다.

이 방식은 빠르게 구현하기에는 좋지만, 기능이 많아질수록 UI와 게임 로직이 강하게 묶이는 문제가 생긴다.


문제점

직접 참조 방식은 다음과 같은 단점이 있다.

  • UI가 특정 액터 구조에 의존한다.
  • 나중에 저장소, 작업대, 퀘스트 보드 구조가 바뀌면 UI도 같이 수정해야 한다.
  • 테스트가 어렵다.
  • UI 코드 안에 데이터 처리 로직이 섞이기 쉽다.
  • 여러 UI가 같은 데이터를 사용할 때 관리가 복잡해진다.

MVVM 방향으로 바꾸려는 이유

MVVM은 UI와 데이터를 중간 계층으로 분리하는 구조다.

간단히 보면 다음과 같다.

Model        : 실제 데이터
ViewModel    : UI에 보여줄 형태로 가공한 데이터
View         : 실제 위젯 화면

즉, 위젯이 데이터를 직접 찾으러 가는 것이 아니라, ViewModel이 UI에 필요한 데이터를 준비하고 위젯은 그것을 표시하는 역할에 집중한다.


변경 방향

기존 방식:

Widget → Actor / Storage / QuestBoard 직접 참조

개선 방향:

Widget → ViewModel → 실제 데이터 / 시스템

이렇게 바꾸면 UI는 “어디서 데이터를 가져오는지”를 몰라도 된다.

위젯은 ViewModel이 제공하는 값만 보고 화면을 갱신하면 된다.


정리

오늘은 카드 뭉치 문제를 풀면서 인덱스를 이용해 순서를 관리하는 방법을 익혔다.

또한 UI 구조에서는 기존 직접 참조 방식이 빠르게 구현하기에는 편하지만, 기능이 커질수록 유지보수가 어려워질 수 있다는 점을 정리했다.

앞으로 작업대, 창고, 퀘스트 보드 UI를 직접 참조 방식에서 ViewModel을 거치는 구조로 바꾸면 UI와 게임 로직의 책임을 더 깔끔하게 나눌 수 있을 것 같다.