카페의 도장 카드를 클래스로 만들어라.
카드 객체는 주인 이름, 목표 도장 수 g, 지금 찍힌 도장 수, 가진 쿠폰 수를 필드로 갖는다.
생성자는 주인 이름과 g를 받고, 도장 수와 쿠폰 수는 0에서 시작한다.
음료를 한 잔 살 때마다 도장을 하나 찍는다. 찍은 뒤 도장 수가 g가 되면 도장 수는 0이 되고 쿠폰이 1장 늘어난다.
첫 줄에 명령 수 q, 다음 q줄에 명령이 하나씩 주어진다.
- new 이름 g: 그 이름의 카드를 목표 g로 새로 만든다. 그 이름의 카드가 이미 있으면 옛 카드를 버리고 새 카드로 바꾼다. 새 카드의 도장 수와 쿠폰 수는 0이다. 출력은 없다.
- buy 이름 k: 그 카드의 주인이 음료를 k잔 산다.
- use 이름: 그 카드에 쿠폰이 있으면 1장 쓴다. 쿠폰이 없으면 아무것도 바꾸지 않는다.
buy와 use를 처리할 때마다 그 카드의 "이름 도장수 쿠폰수"를 빈칸 하나씩 띄워 한 줄에 출력하라.
카드마다 객체를 하나씩 만들고, 도장 찍기·쿠폰 쓰기를 메서드로 만들어 보자.
입력
1 ≤ q ≤ 2,000. 이름은 영어 소문자·숫자 1~10글자다. 1 ≤ g ≤ 100, 1 ≤ k ≤ 100(정수). buy와 use의 이름은 앞의 new로 이미 만들어진 카드이고, buy나 use가 하나 이상 있다
출력
buy와 use마다 한 줄씩, 명령이 나온 차례대로
예시 1 · stdin
8
new ann 3
buy ann 2
buy ann 5
use ann
new bob 1
buy bob 2
use ann
use ann
stdout
ann 2 0
ann 1 2
ann 1 1
bob 0 2
ann 1 0
ann 1 0
예시 2 · stdin
5
new kim 2
buy kim 3
new kim 5
buy kim 1
use kim
stdout
kim 1 1
kim 1 0
kim 1 0
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 6개 언어 풀이
이 문제는 클래스가 있는 Python·JavaScript·TypeScript·Java·C#·C++만 받아요(C에는 클래스가 없고, 크레이콘은 아직 클래스를 만들 수 없어요). 생성자는 Python __init__(self, owner, goal), JS·TS constructor, Java·C#·C++는 클래스와 같은 이름의 메서드예요. TypeScript는 constructor(readonly owner: string, readonly goal: number) {}처럼 매개변수에 readonly·private를 붙이면 필드 선언과 대입을 한 번에 해 줘요. C++는 : owner_(owner), goal_(goal) 초기화 목록을 써요. 필드에 닿는 방법도 달라요: Python은 늘 self.를 써야 하고, JS·TS는 늘 this.를 써야 해요. Java·C#·C++는 this를 빼도 되지만, 매개변수 이름이 필드와 같으면 매개변수가 필드를 가려요. 함정 다섯: ① Java 생성자에서 goal = goal;이라 쓰면 매개변수에 자기 자신을 넣을 뿐이라 필드 goal은 0으로 남고, 도장이 영영 쿠폰이 되지 않아요(this.goal = goal;). 필드가 final이면 컴파일러가 잡아 줘요. ② JS에서 forEach(this.stamp)처럼 메서드를 떼어 넘기면 this가 사라져서 TypeError가 나요. 화살표 함수 () => this.stamp()로 감싸요. ③ C++ std::map의 emplace·insert는 이름이 이미 있으면 아무것도 바꾸지 않아서 new로 다시 만든 카드가 옛 카드로 남아요. insert_or_assign이나 cards[name] = ...이 바꿔요(다만 []는 기본 생성자가 필요해요). ④ C++ StampCard card = cards.at(name);은 복사본이라 고친 도장이 사라져요. StampCard& card로 받아요. C#도 class 대신 struct로 만들면 값 형식이라 사전에서 꺼낼 때마다 복사본이 나와요. ⑤ 쿠폰이 0장일 때 쓰지 않게 막는 일은 use 메서드 안에 한 번만 적어요. 그래야 어디서 불러도 -1장이 되지 않아요.
Pythonmain.py · 46 줄
import sysclass StampCard: def __init__(self, owner, goal): self.owner = owner self.goal = goal self.stamps = 0 self.coupons = 0 def stamp(self): self.stamps += 1 if self.stamps == self.goal: # 목표에 닿으면 쿠폰 한 장으로 바꾼다 self.stamps = 0 self.coupons += 1 def buy(self, k): for _ in range(k): self.stamp() def use(self): if self.coupons == 0: return False self.coupons -= 1 return True def describe(self): return f"{self.owner} {self.stamps} {self.coupons}"lines = sys.stdin.read().split("\n")q = int(lines[0])cards = {}out = []for line in lines[1 : q + 1]: p = line.split() if p[0] == "new": cards[p[1]] = StampCard(p[1], int(p[2])) # 이미 있으면 새 카드로 바뀐다 else: card = cards[p[1]] if p[0] == "buy": card.buy(int(p[2])) else: card.use() out.append(card.describe())print("\n".join(out))
JavaScriptmain.js · 48 줄
class StampCard { constructor(owner, goal) { this.owner = owner; this.goal = goal; this.stamps = 0; this.coupons = 0; } stamp() { this.stamps++; if (this.stamps === this.goal) { // 목표에 닿으면 쿠폰 한 장으로 바꾼다 this.stamps = 0; this.coupons++; } } buy(k) { for (let i = 0; i < k; i++) this.stamp(); } use() { if (this.coupons === 0) return false; this.coupons--; return true; } describe() { return `${this.owner} ${this.stamps} ${this.coupons}`; }}const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const cards = new Map();const out = [];for (let i = 1; i <= q; i++) { const [cmd, name, num] = lines[i].trim().split(" "); if (cmd === "new") { cards.set(name, new StampCard(name, Number(num))); // 이미 있으면 새 카드로 바뀐다 continue; } const card = cards.get(name); if (cmd === "buy") card.buy(Number(num)); else card.use(); out.push(card.describe());}console.log(out.join("\n"));
TypeScriptmain.ts · 49 줄
import { readFileSync } from "node:fs";class StampCard { private stamps = 0; private coupons = 0; // 매개변수 앞의 readonly가 같은 이름의 필드를 만들고 값을 넣어 준다 constructor(readonly owner: string, readonly goal: number) {} private stamp(): void { this.stamps++; if (this.stamps === this.goal) { // 목표에 닿으면 쿠폰 한 장으로 바꾼다 this.stamps = 0; this.coupons++; } } buy(k: number): void { for (let i = 0; i < k; i++) this.stamp(); } use(): boolean { if (this.coupons === 0) return false; this.coupons--; return true; } describe(): string { return `${this.owner} ${this.stamps} ${this.coupons}`; }}const lines: string[] = readFileSync(0, "utf8").split("\n");const q: number = Number(lines[0]);const cards = new Map<string, StampCard>();const out: string[] = [];for (let i = 1; i <= q; i++) { const [cmd, name, num] = lines[i].trim().split(" "); if (cmd === "new") { cards.set(name, new StampCard(name, Number(num))); // 이미 있으면 새 카드로 바뀐다 continue; } const card = cards.get(name)!; if (cmd === "buy") card.buy(Number(num)); else card.use(); out.push(card.describe());}console.log(out.join("\n"));
JavaMain.java · 59 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.HashMap;import java.util.Map;class StampCard { private final String owner; private final int goal; private int stamps = 0; private int coupons = 0; StampCard(String owner, int goal) { this.owner = owner; // this. 가 없으면 매개변수에 자기 자신을 넣을 뿐이다 this.goal = goal; } private void stamp() { stamps++; if (stamps == goal) { // 목표에 닿으면 쿠폰 한 장으로 바꾼다 stamps = 0; coupons++; } } void buy(int k) { for (int i = 0; i < k; i++) stamp(); } boolean use() { if (coupons == 0) return false; coupons--; return true; } String describe() { return owner + " " + stamps + " " + coupons; }}public class Main { public static void main(String[] args) throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int q = Integer.parseInt(in.readLine().trim()); Map<String, StampCard> cards = new HashMap<>(); StringBuilder out = new StringBuilder(); for (int i = 0; i < q; i++) { String[] p = in.readLine().trim().split(" "); if (p[0].equals("new")) { cards.put(p[1], new StampCard(p[1], Integer.parseInt(p[2]))); // 이미 있으면 새 카드로 바뀐다 continue; } StampCard card = cards.get(p[1]); if (p[0].equals("buy")) card.buy(Integer.parseInt(p[2])); else card.use(); out.append(card.describe()).append('\n'); } System.out.print(out); }}
C#Main.cs · 65 줄
using System;using System.Collections.Generic;using System.Text;class StampCard // struct로 만들면 사전에서 꺼낼 때마다 복사본이 나온다{ public string Owner { get; } public int Goal { get; } public int Stamps { get; private set; } public int Coupons { get; private set; } public StampCard(string owner, int goal) { Owner = owner; Goal = goal; } private void Stamp() { Stamps++; if (Stamps == Goal) // 목표에 닿으면 쿠폰 한 장으로 바꾼다 { Stamps = 0; Coupons++; } } public void Buy(int k) { for (int i = 0; i < k; i++) Stamp(); } public bool Use() { if (Coupons == 0) return false; Coupons--; return true; } public override string ToString() => $"{Owner} {Stamps} {Coupons}";}class Program{ static void Main() { int q = int.Parse(Console.ReadLine()!.Trim()); var cards = new Dictionary<string, StampCard>(); var sb = new StringBuilder(); for (int i = 0; i < q; i++) { string[] p = Console.ReadLine()!.Trim().Split(' '); if (p[0] == "new") { cards[p[1]] = new StampCard(p[1], int.Parse(p[2])); // 이미 있으면 새 카드로 바뀐다 continue; } StampCard card = cards[p[1]]; if (p[0] == "buy") card.Buy(int.Parse(p[2])); else card.Use(); sb.Append(card).Append('\n'); } Console.Write(sb); }}
C++main.cpp · 62 줄
#include <iostream>#include <map>#include <string>class StampCard {public: StampCard(std::string owner, int goal) : owner_(std::move(owner)), goal_(goal) {} void buy(int k) { for (int i = 0; i < k; i++) stamp(); } bool use() { if (coupons_ == 0) return false; coupons_--; return true; } std::string describe() const { return owner_ + " " + std::to_string(stamps_) + " " + std::to_string(coupons_); }private: void stamp() { stamps_++; if (stamps_ == goal_) { // 목표에 닿으면 쿠폰 한 장으로 바꾼다 stamps_ = 0; coupons_++; } } std::string owner_; int goal_; int stamps_ = 0; int coupons_ = 0;};int main() { std::ios::sync_with_stdio(false); int q; std::cin >> q; std::map<std::string, StampCard> cards; for (int i = 0; i < q; i++) { std::string cmd, name; std::cin >> cmd >> name; if (cmd == "new") { int g; std::cin >> g; cards.insert_or_assign(name, StampCard(name, g)); // emplace·insert는 이미 있으면 바꾸지 않는다 continue; } StampCard& card = cards.at(name); // &가 없으면 복사본을 고친다 if (cmd == "buy") { int k; std::cin >> k; card.buy(k); } else { card.use(); } std::cout << card.describe() << '\n'; }}