Skip to content

Commit 611d238

Browse files
committed
feat(tasks): Add FPS24 (#2796)
1 parent 287afa5 commit 611d238

File tree

10 files changed

+420
-9
lines changed

10 files changed

+420
-9
lines changed
Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
# FPS24(24 Problems on Formal Power Series)のコンテスト対応実装計画
2+
3+
## 📋 概要
4+
5+
FPS24 コンテスト対応として、`ContestType` enum に `FPS_24` を追加し、コンテスト ID `fps-24` の問題をインポートできるようにする実装計画です。
6+
7+
参考実装: [PR #1335: Add AXC-like contests](https://github.com/AtCoder-NoviSteps/AtCoderNoviSteps/commit/193bd801eca7e3274e980e31758edd1d46a9a27b)
8+
9+
## 🎯 実装スコープ
10+
11+
### ✅ 実装対象
12+
13+
1. **Prisma スキーマ更新**
14+
- `prisma/schema.prisma``ContestType` enum に `FPS_24` を追加
15+
- 配置: `UNIVERSITY` の後、`OTHERS` の前
16+
17+
2. **Prisma マイグレーション**
18+
- 新規マイグレーションファイル作成: `add_fps_24_to_contest_type`
19+
- コマンド: `pnpm dlx prisma migrate dev --name add_fps_24_to_contest_type`
20+
21+
3. **ERD.md の手動更新**
22+
- マイグレーション実行後、ER図に `FPS_24` を追加
23+
24+
4. **型定義の更新**
25+
- `src/lib/types/contest.ts``FPS_24` を追加
26+
27+
5. **コンテスト分類ロジックの更新**
28+
- `src/lib/utils/contest.ts``classifyContest` 関数に FPS24 判定ロジックを追加
29+
- 判定条件: `contest_id === 'fps-24'` (完全一致)
30+
- 戻り値: `ContestType.FPS_24`
31+
32+
6. **優先度定義の更新**
33+
- `src/lib/utils/contest.ts``contestTypePriorities` Map に FPS24 を追加
34+
- 優先度: 17(UNIVERSITY の次)
35+
- 優先度: UNIVERSITY は 16、FPS_24 は 17、OTHERS は 18 に変更
36+
37+
7. **コンテスト名ラベルの更新**
38+
- `src/lib/utils/contest.ts``getContestNameLabel` 関数に FPS24 判定ロジックを追加
39+
- 判定条件: `contest_id === 'fps-24'` (完全一致)
40+
- 戻り値: `'FPS 24 題'`
41+
- 追加位置: `math-and-algorithm` の判定の後、`regexForAtCoderUniversity` の判定の前
42+
43+
8. **テスト実装**
44+
- `src/test/lib/utils/contest.test.ts` に FPS24 相当テストケースを追加
45+
- テストコンテスト ID: `fps-24`
46+
47+
9. **ERD.md(自動生成後の手動確認)**
48+
- マイグレーション後に `prisma generate` で ERD.md が自動更新される
49+
- 手動で `FPS_24` が正しく反映されているか確認
50+
51+
## 🔍 実装パターン(参考 PR より)
52+
53+
### enum 値の追加パターン
54+
55+
```prisma
56+
enum ContestType {
57+
// 既存の値...
58+
UNIVERSITY // University Programming Contests in AtCoder (e.g., UTPC)
59+
FPS_24 // 24 Problems on Formal Power Series
60+
OTHERS // AtCoder (その他)
61+
// その他...
62+
}
63+
```
64+
65+
### 型定義のパターン
66+
67+
```typescript
68+
export const ContestType: { [key in ContestTypeOrigin]: key } = {
69+
// 既存の値...
70+
UNIVERSITY: 'UNIVERSITY',
71+
FPS_24: 'FPS_24',
72+
OTHERS: 'OTHERS',
73+
// その他...
74+
};
75+
```
76+
77+
### コンテスト分類ロジックのパターン
78+
79+
```typescript
80+
export const classifyContest = (contest_id: string) => {
81+
// ... 既存のロジック ...
82+
83+
// FPS24 判定(新規追加)
84+
if (contest_id === 'fps-24') {
85+
return ContestType.FPS_24;
86+
}
87+
88+
// ... その他のロジック ...
89+
};
90+
```
91+
92+
### 優先度定義のパターン
93+
94+
```typescript
95+
export const contestTypePriorities: Map<ContestType, number> = new Map([
96+
// 既存の値...
97+
[ContestType.UNIVERSITY, 16],
98+
[ContestType.FPS_24, 17], // 新規追加
99+
[ContestType.OTHERS, 18], // 従来の 17 から 18 に変更
100+
// その他...
101+
]);
102+
```
103+
104+
### コンテスト名ラベルのパターン
105+
106+
```typescript
107+
export const getContestNameLabel = (contestId: string) => {
108+
// ... 既存のロジック ...
109+
110+
if (contestId === 'math-and-algorithm') {
111+
return 'アルゴリズムと数学';
112+
}
113+
114+
// FPS24 判定(新規追加)
115+
if (contestId === 'fps-24') {
116+
return 'FPS 24 題';
117+
}
118+
119+
// ... その他のロジック ...
120+
};
121+
```
122+
123+
## 📝 実装ファイル一覧
124+
125+
| ファイル | 操作 | 内容 |
126+
| --------------------------------------------------------------------------- | ---- | --------------------------------------------------------------------------------------- |
127+
| `prisma/schema.prisma` | 更新 | `ContestType` enum に `FPS_24` を追加 |
128+
| `prisma/migrations/YYYYMMDDHHMMSS_add_fps_24_to_contest_type/migration.sql` | 作成 | ALTER TYPE コマンド(自動生成) |
129+
| `prisma/ERD.md` | 更新 | `FPS_24` が enum 値に反映されているか確認 |
130+
| `src/lib/types/contest.ts` | 更新 | `ContestType` 型定義に `FPS_24` を追加 |
131+
| `src/lib/utils/contest.ts` | 更新 | `classifyContest`, `contestTypePriorities`, `getContestNameLabel` に FPS24 ロジック追加 |
132+
| `src/test/lib/utils/contest.test.ts` | 更新 | FPS24 関連テストケースを追加 |
133+
134+
## 🧪 テストケース例
135+
136+
### コンテスト分類テスト
137+
138+
```typescript
139+
describe('when contest_id means fps-24', () => {
140+
const testCases = [{ contestId: 'fps-24', expected: ContestType.FPS_24 }];
141+
142+
runTests('classifyContest', testCases, ({ contestId, expected }: TestCaseForContestType) => {
143+
expect(classifyContest(contestId)).toEqual(expected);
144+
});
145+
});
146+
```
147+
148+
### 優先度テスト
149+
150+
```typescript
151+
describe('when contest_id means fps-24 (priority)', () => {
152+
const testCases = [{ contestId: 'fps-24', expected: ContestType.FPS_24 }];
153+
154+
runTests('getContestPriority', testCases, ({ contestId, expected }: TestCaseForContestType) => {
155+
expect(getContestPriority(contestId)).toEqual(contestTypePriorities.get(expected));
156+
});
157+
});
158+
```
159+
160+
### コンテスト名ラベルテスト
161+
162+
```typescript
163+
describe('when contest_id is fps-24', () => {
164+
const testCases = [{ contestId: 'fps-24', expected: 'FPS 24 題' }];
165+
166+
runTests(
167+
'getContestNameLabel',
168+
testCases,
169+
({ contestId, expected }: TestCaseForContestNameLabel) => {
170+
expect(getContestNameLabel(contestId)).toEqual(expected);
171+
},
172+
);
173+
});
174+
```
175+
176+
## 📋 実装手順
177+
178+
### フェーズ 1: Prisma スキーマ更新
179+
180+
1. `prisma/schema.prisma` を開く
181+
2. `ContestType` enum の `UNIVERSITY` の後に `FPS_24` を追加
182+
3. コマンドを実行: `pnpm dlx prisma migrate dev --name add_fps_24_to_contest_type`
183+
4. マイグレーション SQL ファイルが自動生成される
184+
5. `prisma/ERD.md` を確認して `FPS_24` が反映されているか確認
185+
186+
### フェーズ 2: 型定義とロジックの更新
187+
188+
1. `src/lib/types/contest.ts` を更新(`FPS_24` を追加)
189+
2. `src/lib/utils/contest.ts` を更新:
190+
- `classifyContest` 関数に FPS24 判定ロジックを追加
191+
- `contestTypePriorities` Map に `[ContestType.FPS_24, 17]` を追加
192+
- `UNIVERSITY` は 16 のまま、`OTHERS` の優先度を 18 に変更
193+
- `getContestNameLabel` 関数に FPS24 ラベル処理を追加(戻り値: `'FPS 24 題'`
194+
195+
### フェーズ 3: テスト実装
196+
197+
1. `src/test/lib/utils/test_cases/contest_type.ts` を更新:
198+
- FPS24 テストケースデータを追加
199+
2. `src/test/lib/utils/test_cases/contest_name_labels.ts` を更新:
200+
- FPS24 ラベルテストケースデータを追加(`contestId: 'fps-24'`, `expected: 'FPS 24 題'`
201+
3. `src/test/lib/utils/contest.test.ts` を更新:
202+
- FPS24 分類テスト(`classifyContest`)を追加
203+
- FPS24 優先度テスト(`getContestPriority`)を追加
204+
- FPS24 ラベルテスト(`getContestNameLabel`)を追加
205+
4. テスト実行: `pnpm test:unit`
206+
207+
### フェーズ 4: 検証
208+
209+
1. ローカルでテスト実行: `pnpm test:unit`
210+
2. 全テストが PASS であることを確認
211+
3. Prisma Client が正しく生成されているか確認: `pnpm dlx prisma generate`
212+
213+
## ✅ チェックリスト
214+
215+
### 実装完了時の確認項目
216+
217+
- [ ] Prisma スキーマに `FPS_24` が追加されている
218+
- [ ] マイグレーション SQL が正しく生成されている
219+
- [ ] `prisma/ERD.md``FPS_24` が反映されている
220+
- [ ] `src/lib/types/contest.ts``FPS_24: 'FPS_24'` が追加されている
221+
- [ ] `src/lib/utils/contest.ts``classifyContest` に FPS24 ロジックが実装されている
222+
- [ ] `src/lib/utils/contest.ts``contestTypePriorities``[ContestType.FPS_24, 17]` が追加されている
223+
- [ ] `src/lib/utils/contest.ts``OTHERS` の優先度が 18 に更新されている
224+
- [ ] `src/lib/utils/contest.ts``getContestNameLabel` に FPS24 ラベル処理が実装されている(戻り値: `'FPS 24 題'`
225+
- [ ] `src/test/lib/utils/test_cases/contest_type.ts` に FPS24 テストケースが追加されている
226+
- [ ] `src/test/lib/utils/test_cases/contest_name_labels.ts` に FPS24 ラベルテストケースが追加されている
227+
- [ ] `src/test/lib/utils/contest.test.ts` に FPS24 テストが追加されている
228+
- [ ] `pnpm test:unit` が全て PASS している
229+
- [ ] Prisma Client が正しく生成されている(`pnpm dlx prisma generate`
230+
231+
## 📚 参考ドキュメント
232+
233+
### 指示ファイル(プロジェクト品質基準)
234+
235+
- `global.instructions.md`: プロジェクト全体の統一設定
236+
- `source-code.instructions.md`: ソースコード構造とアーキテクチャ
237+
- `tests.instructions.md`: テスト戦略(Vitest v3.2.4)
238+
- `ci.instructions.md`: CI/CD 設定
239+
240+
### 重要な制約
241+
242+
- **TypeScript**: `strict: true` 必須
243+
- **テスト**: Vitest v3.2.4 以上
244+
- **命名規則**: enum は UPPER_SNAKE_CASE
245+
- **Prisma**: キャメルケースでモデル定義
246+
247+
### 外部参照
248+
249+
- [AtCoder FPS24](https://atcoder.jp/contests/fps-24)
250+
- [Prisma Documentation](https://www.prisma.io/docs/)
251+
- [参考 PR: Add AXC-like contests](https://github.com/AtCoder-NoviSteps/AtCoderNoviSteps/commit/193bd801eca7e3274e980e31758edd1d46a9a27b)
252+
253+
## 🔗 関連タスク
254+
255+
- FPS24 の問題インポート処理の実装(別タスク)
256+
- CI/CD でのテスト実行確認
257+
- ドキュメント更新(必要に応じて)
258+
259+
## 🚀 将来の課題: FPS24 のコンテスト表テーブル実装
260+
261+
> **状態**: 未着手(将来の拡張予定)
262+
> **参考**: [PR #2786: Add math and algo book to contest table](https://github.com/AtCoder-NoviSteps/AtCoderNoviSteps/pull/2786)
263+
264+
### 概要
265+
266+
本実装(Prisma スキーマ更新)の後、FPS24 をコンテスト表テーブルに表示するための UI Provider を実装する予定です。
267+
268+
参考 PR #2786 では「Math and Algorithm」コンテストについて、以下を実装しています:
269+
270+
- 問題データの追加(`prisma/tasks.ts`
271+
- UI Provider の実装(`src/lib/utils/contest_table_provider.ts`
272+
- テストケースの追加
273+
274+
### 実装予定
275+
276+
1. **問題データの追加**
277+
- `prisma/tasks.ts` に FPS24 の問題定義を追加
278+
- 問題ペアデータはコンテスト内で完結(`contest_task_pairs` は不使用)
279+
280+
2. **UI Provider の実装**
281+
- `src/lib/utils/contest_table_provider.ts``FPS24Provider` を実装
282+
- または既存の provider フレームワークを拡張
283+
- 以下の機能を実装:
284+
- 問題フィルタリング
285+
- メタデータ管理
286+
- テーブルレイアウト設定(ヘッダーやラウンドラベルの表示/非表示)
287+
288+
3. **テストの追加**
289+
- `src/test/lib/utils/contest_table_provider.test.ts` に FPS24 Provider テストを追加
290+
- モックデータの作成(`src/test/lib/utils/test_cases/contest_table_provider.ts`
291+
292+
### 関連ファイル
293+
294+
| ファイル | 説明 |
295+
| --------------------------------------------------------- | -------------------- |
296+
| `prisma/tasks.ts` | FPS24 問題定義の追加 |
297+
| `src/lib/utils/contest_table_provider.ts` | UI Provider 実装 |
298+
| `src/test/lib/utils/contest_table_provider.test.ts` | Provider テスト |
299+
| `src/test/lib/utils/test_cases/contest_table_provider.ts` | モックデータ定義 |
300+
301+
### 優先度
302+
303+
このタスクは、本実装(Prisma スキーマ + 基本ロジック)が完了した後に着手することを想定しています。
304+
305+
## 📚 実装から得られた教訓
306+
307+
### 実装完了時の状態
308+
309+
✅ 全チェックリスト項目を完了
310+
✅ テスト 817 件全て PASS(FPS24 関連テスト含む)
311+
✅ Prisma Client 正常に生成
312+
313+
### 主な学習ポイント
314+
315+
1. **Prisma Enum 追加の手順**
316+
- `schema.prisma` の enum 定義に追加
317+
- `pnpm dlx prisma migrate dev --name` で自動マイグレーション生成
318+
- 型安全性を保つために Prisma Client が自動再生成される
319+
320+
2. **型定義と実装の対応**
321+
- Prisma enum → TypeScript 型オブジェクト(`as const` 指定)
322+
- テストケースデータの構造化により、テスト追加時の漏れを防止
323+
- ランダムテスト名の生成で重複チェック可能
324+
325+
3. **コンテスト分類ロジック(優先度順)の統一性**
326+
- 判定は具体的 → 一般的へ段階的に実施
327+
- 完全一致(`contest_id === 'fps-24'`)を前にチェック
328+
- 優先度 Map で順序を一元管理(追加時に他の値も調整必要)
329+
330+
4. **テスト構造の再利用性**
331+
- テストケースを「data」ファイルと「test」ファイルで分離
332+
- 複数テスト関数(`classifyContest`, `getContestPriority`, `getContestNameLabel`)を同じデータで検証
333+
- テスト数が増えても保守性が維持される設計
334+
335+
5. **参考 PR パターンの活用**
336+
- 小さな変更でも参考 PR から実装パターンを確認
337+
- UPPER_SNAKE_CASE、判定条件のルール、優先度番号付けなど
338+
- 既存コードとの一貫性が重要
339+
340+
### 今後の参考
341+
342+
- UI Provider 実装時も同じテストケース構造を踏襲
343+
- `contest_table_provider.ts` に新規ロジック追加時の参考になる
344+
- テスト駆動で実装する場合も、テストケースデータを先に定義すると効率的

prisma/ERD.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ ABC_LIKE ABC_LIKE
2626
ARC_LIKE ARC_LIKE
2727
AGC_LIKE AGC_LIKE
2828
UNIVERSITY UNIVERSITY
29+
FPS_24 FPS_24
2930
OTHERS OTHERS
3031
AOJ_COURSES AOJ_COURSES
3132
AOJ_PCK AOJ_PCK
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterEnum
2+
ALTER TYPE "ContestType" ADD VALUE 'FPS_24';
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Please do not edit this file manually
2-
# It should be added in your version-control system (e.g., Git)
3-
provider = "postgresql"
2+
# It should be added in your version-control system (i.e. Git)
3+
provider = "postgresql"

prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ enum ContestType {
238238
ARC_LIKE // AtCoder Regular Contest (ARC) 相当のコンテスト
239239
AGC_LIKE // AtCoder Grand Contest (AGC) 相当のコンテスト
240240
UNIVERSITY // University Programming Contests in AtCoder (e.g., UTPC)
241+
FPS_24 // 24 Problems on Formal Power Series
241242
OTHERS // AtCoder (その他)
242243
AOJ_COURSES // AIZU ONLINE JUDGE Courses
243244
AOJ_PCK // All-Japan High School Programming Contest (PCK)

src/lib/types/contest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const ContestType: { [key in ContestTypeOrigin]: key } = {
4545
ARC_LIKE: 'ARC_LIKE', // AtCoder Regular Contest (ARC) 相当のコンテスト
4646
AGC_LIKE: 'AGC_LIKE', // AtCoder Grand Contest (AGC) 相当のコンテスト
4747
UNIVERSITY: 'UNIVERSITY', // University Programming Contests in AtCoder (e.g., UTPC)
48+
FPS_24: 'FPS_24', // 24 Problems on Formal Power Series
4849
OTHERS: 'OTHERS', // AtCoder (その他)
4950
AOJ_COURSES: 'AOJ_COURSES', // AIZU ONLINE JUDGE Courses
5051
AOJ_PCK: 'AOJ_PCK', // All-Japan High School Programming Contest (PCK)

0 commit comments

Comments
 (0)