Home

포켓몬스터 TCG 모바일 클론코딩

개요

이런 형태의 카드를 본 적이 있는가? 문방구나 편의점에서 쉽게 볼 수 있는 일명 포켓몬 카드는 단순 수집용이 아니라 나름의 체계적인 룰을 갖춘 유명한 게임이다.
오프라인을 넘어, 드디어 작년에 모바일로도 포켓몬 카드게임을 즐길 수 있게 되었다.
팩을 뜯고 카드를 모으고 이런 부분보다는 카드 배틀 진행 부분을 클론코딩 해보려고 한다. 이 앱은 유저간 배틀 뿐 아니라 봇전도 지원하는데, 레벨별로 알고리즘이 달라지는 것 같다고 느꼈다. 이 알고리즘을 어디까지 향상시킬 수 있을까? 유저가 사고하는 방식 그대로 할 수 있을까? 룰이 그렇게 어려운 게임은 아니기 때문에 충분히 가능하리라고 생각했고, 처음에는 이 부분을 설계해보고 싶었다. 다만 카드, 동전, 에너지 등, 게임 자체에 대해 객체지향적으로 접근할 수 있을 것 같아 클론코딩을 해보려고 한다.

요구사항 정리하고 구현하기

동전

요구사항

동전(Coin)
참고자료
양면 정의
동전은 반드시 두 가지 면, 즉 앞면(HEADS)과 뒷면(TAILS)를 가져야 합니다.
랜덤성 및 50/50 확률
동전을 던졌을 때 앞면과 뒷면이 나올 확률이 동일해야 합니다.
상태 관리
동전 객체는 현재의 면 상태(마지막으로 나온 결과)를 저장할 수 있어야 합니다.
동전을 던지는 세 가지 루틴(CoinFilp)
1.
뒷면이 나올 때까지 던지는 루틴
동전을 연속해서 던져서 뒷면(TAILS)이 처음 나올때까지 진행한 후, 그 사이에 나온 앞면(HEADS)의 횟수를 반환합니다.
동작 방식
a.
동전을 한 번 던진다.
b.
결과가 앞면(HEADS)면 카운트를 1 증가시키고, 다시 던진다.
c.
결과가 뒷면(TAILS)면 루프를 종료한다.
반환 값(Return)
앞면(HEADS)가 나온 총 횟수
2.
정해진 횟수만큼 던지는 루틴
사용자가 지정한 횟수(n)만큼 동전을 던진 후, 그 중 앞면(HEADS)가 나온 횟수를 반환합니다.
동작 방식
a.
사용자로부터 던질 횟수(n)을 파라미터로 받는다.
b.
n번 반복하면서 매번 동전을 던진다.
c.
결과가 앞면(HEADS)면 카운트를 1 증가시킨다.
d.
모든 반복 후 앞면(HEADS)의 총 횟수를 반환한다.
반환값(Return)
앞면(HEADS)가 나온 총 횟수
3.
한번만 던지는 루틴
동전을 단 한 번 던져서, 그 결과가 앞면(HEADS)인지 뒷면(TAILS)인지를 판단하여 반환합니다.
동작 방식
a.
동전을 한 번 던진다.
b.
결과(HEADS 또는 TAILS)를 즉시 출력한다.
c.
결과가 HEADS이면 true, TAILS이면 false로 반환하거나, 결과 자체를 그대로 반환할 수 있다.
반환 값
Boolean 값(true: 앞면, false: 뒷면) 또는 결과(enum 값)를 반환

구현

 Coin/CoinFace
 코인은 양면을 가집니다. 따라서 CoinFace 라는 Enum 객체를 생성하고, Coin 클래스에 CoinFace 타입의 필드를 두겠습니다.
public enum CoinFace { HEADS, TAILS }
Java
복사
public class Coin { private CoinFace currentFace; public Coin() { this.currentFace = null; } public CoinFace getCurrentFace() { return currentFace; } public void setCurrentFace(CoinFace coinFace) { this.currentFace = coinFace; } }
Java
복사
 Coin 객체를 처음 생성하면, 동전은 던져지지 않은 상태일테니 currentFace 는 null이 됩니다.
  Coin 은 1개를 계속해서 재사용합니다. 따라서 settergetter 를 두어 동전을 던질 때 앞면/뒷면 여부를 할당하고 get할 수 있게 합니다.
 CoinFlipper
 동전을 던지는 행동을 수행하는 객체를 만들겠습니다.
public class CoinFlipper { private Random random; public CoinFlipper() { random = new Random(); } public Coin flip(Coin coin) { CoinFace result = random.nextBoolean() ? CoinFace.HEADS : CoinFace.TAILS; coin.setCurrentFace(result); System.out.println("동전 결과: " + result); return coin; } }
Java
복사
 앞면 혹은 뒷면이 나올 확률은 각각 1/2씩입니다. 자바는 Random 객체의 nextBoolean() 메서드를 통해 0 혹은 1이 나올 확률을 반반으로 제공합니다. (실제 반반인지는 운에 맡기는걸로)
 CoinTossService
 게임에서, 동전은 보통 3가지 방식으로 사용됩니다. 외부에서 Coin 이나 CoinFlipper 를 사용해야 할 때, 동일한 기능을 제공해 줄 객체가 필요합니다. 이 객체를 CoinTossService 라고 명명하겠습니다.
public class CoinTossService { private final CoinFlipper coinFlipper; public CoinTossService(CoinFlipper coinFlipper) { this.coinFlipper = coinFlipper; } }
Java
복사
 가장 간단한 3. 한번만 던지는 루틴을 구현해보겠습니다. 내부에 정의된 CoinFlipper 를 사용해 동전을 던진 후 해당 객체를 반환합니다.
public Coin flip(Coin coin) { return coinFlipper.flip(coin); }
Java
복사
 1. 뒷면이 나올 때까지 던지는 루틴2. 정해진 횟수만큼 던지는 루틴도 반복문으로 간단하게 구현할 수 있습니다.
public int flipUntilTails(Coin coin) { int count = 0; while (coinFlipper.flip(coin).getCurrentFace() == CoinFace.HEADS) { count++; } return count; } public int flipMultiple(Coin coin, int energyCount) { int count = 0; for (int i = 0; i< energyCount; i++) { if(coinFlipper.flip(coin).getCurrentFace() == CoinFace.HEADS) { count++; } } return count; }
Java
복사
 가장 기본적인 Coin 에 대한 정의가 끝났습니다. 여러 개선사항이 눈에 보이지만 최소한의 SRP 를 준수하면서 클래스의 관심사가 각각 분리되는 정도는 되었습니다. 동전을 던지는 기능을 수행할 때 문제가 될 부분은 일단 없어보입니다. 이제 가장 핵심인 카드 구현으로 넘어가 보겠습니다.

카드

요구사항

카드의 종류는 5가지로 나뉩니다.
포켓몬 카드
트레이너 카드
아이템 카드
아이템(화석) 카드