この問題はクラスのある Python・JavaScript・TypeScript・Java・C#・C++ だけを受け付けます(C にはクラスがなく、Craykon はまだクラスを作れません)。
コンストラクタは 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 sys class 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'; }}