npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@amas.nghia/todaycode-missions

v0.1.0

Published

Missions rulebook — implements the todaycode-game-engine Engine contract; single source of CodeClash mission rules for todaycode-be and CodeClash-fe.

Readme

todaycode-missions

Quyển luật của game Missions — 213 màn học Python theo giáo trình CodeClash (CS1: 61 · CS2: 78 · CS3: 74; học sinh vào vai wizard, viết Python vượt màn) — implement Engine contract của todaycode-game-engine. Luật tính ở hai nơi (browser chạy thử + server chấm chính thức) nên viết một lần ở đây.

Trạng thái: Phase P0 — MOVE/ATTACK/PICK_UP + 7 loại điều kiện thắng. Xem P0_REVIEW.md trước khi code tiếp.

Khác farmwars một điểm quan trọng: không có bot đối kháng — "đối thủ" là map + điều kiện thắng. Và vì code học sinh đọc state giữa chừng (while wizard.mana >= 20:), runner phải chạy xen kẽ từng lệnh chứ không gom cả turn.

Module nào làm gì — cho ai

| Module | Làm gì | Ai dùng | |---|---|---| | missions.engine.ts | MissionsEngine implements Engine; isOver tự dừng khi thắng (kể cả học sinh viết while True:) | Runner FE/BE | | tick.ts | Trái tim luật: MOVE (theo steps, dừng khi bump), ATTACK (Manhattan ≤ 1), PICK_UP; phát events cho animation | Runner mỗi lệnh | | selectors.ts | Hàm chỉ đọc: findNearestEnemy (hoà → id nhỏ thắng), isPathClear, distanceTo, wizardView | Runner trả lời API quan sát của Python — FE/BE cùng gọi một bộ nên không lệch | | win-conditions.ts | Evaluator theo nguyên văn schema giáo trình {mode, conditions[]} (26 type, P0 evaluate 7) + MissionGrader → passed/stars/metrics | Chấm cuối màn; isOver mỗi bước | | level-schema.ts | MissionDefinition + validateLevel (throw khi thiếu goal/entities) | Người soạn 213 level JSON | | orders.ts | MOVE / ATTACK / PICK_UP / META (META = runner gửi statementCount đếm bằng Python AST) | Runner dịch mỗi wizard.* thành 1 order |

Dùng thế nào — chạy một màn từ đầu đến cuối

import { MissionsEngine, type MissionOrder } from '@amas-nghia/todaycode-missions'
import { findNearestEnemy, wizardView } from '@amas-nghia/todaycode-missions'

// 1. Level — đây là format 213 màn sẽ được soạn
const level = {
  slug: 'cs1-01', version: 1, gameSlug: 'missions',
  definition: {
    course: 'cs1', chapter: 1, coordinateSystem: 'grid',
    map: { width: 6, height: 3, walls: [] },
    wizard: { x: 0, y: 0, health: 100, mana: 100 },
    entities: [{ kind: 'goal', x: 5, y: 0 }],
    apiAllowlist: ['move_right'],          // runner chặn API ngoài danh sách này
  },
  grading: {
    win_conditions: { mode: 'all', conditions: [
      { type: 'reach_goal' },
      { type: 'max_statements', max: 10 },
    ] },
  },
}

// 2. Init
const engine = new MissionsEngine()
let state = engine.init(level, /* seed */ 0)

// 3. Runner dịch code học sinh thành orders — mỗi wizard.* = 1 order.
//    META gửi MỘT LẦN đầu trận: số statement đếm bằng Python AST.
const orders: MissionOrder[] = [
  { op: 'META', statementCount: 5 },
  { op: 'MOVE', dir: 'right', steps: 5 },  // = wizard.move_right() ×5 hoặc move("right", 5)
]

// 4. Chạy XEN KẼ: đẩy order → tick → Python đọc state qua selectors → order tiếp
for (const order of orders) {
  state = engine.applyOrders(state, 0, [order])
  const { events } = engine.tick(state, 0)   // events: 'moved', 'bump', 'attacked'… → FE vẽ
  // Giữa các order, code Python có thể hỏi:
  //   wizard.health          → wizardView(state)
  //   find_nearest_enemy()   → findNearestEnemy(state)
  if (engine.isOver(state)) break             // màn tự dừng ngay khi thắng
}

// 5. Chấm điểm
console.log(engine.result(state))
// → { over: true, passed: true, stars: 3,
//     metrics: { statementCount: 5, ordersExecuted: 2, ... } }

Việc không thuộc package này (runner của app làm): chạy Python (Pyodide/ sandbox), đếm statement bằng AST, chặn API theo apiAllowlist, giới hạn số bước (chống while True: không lối thoát).

Implement thế nào

Thêm một loại điều kiện thắng (việc thường gặp nhất, P1–P3)

  1. win-conditions.ts — type đã khai đủ 26 trong union WinConditionType; thêm nhánh if (cond.type === '...') trong evaluateCondition (đang throw not implemented). Cần dữ liệu mới thì thêm counter vào MissionState (state.ts) và cập nhật trong tick.ts (vd saidStrings cho say_string).
  2. Test: 1 case pass + 1 case fail trong __tests__/win-conditions.spec.ts.
  3. Golden fixture: level dùng condition mới + orders + expected outcome (__tests__/fixtures/, chạy qua determinism spec).
  4. Release: build + commit dist + tag.

Thêm một lệnh wizard mới (vd SAY, CAST)

orders.ts (variant mới) → tick.ts (xử lý + event mới trong events.ts + counter nếu cần chấm điểm) → test + fixture → đồng bộ runner ở app (dịch wizard.say(...) thành order, thêm vào apiAllowlist của các màn liên quan).

Soạn level mới

Theo MissionDefinition (ví dụ ở trên). Nguồn nội dung 213 màn: thiết kế từng màn trong curriculum (man-choi/ch01…ch08.md — map ASCII, starter, giải mẫu, win, hints). Quy ước: reach_goal cần entity goal; boss ≥ 3 conditions; validateLevel throw nếu thiếu goal/entities.

Lộ trình

| Phase | Phạm vi | Tag | |---|---|---| | P0 ← hiện tại | MOVE/ATTACK/PICK_UP + 7 win-type | v0.1.0 | | P1 | SAY/CAST + mana + đủ 14 win-type CS1 | v0.2.0 | | P2 | Toạ độ xy: MOVE_TO, distanceTo, defeat_type… (CS2) | v0.3.0 | | P3 | Events, collections, boss đa phase (CS3) | v0.4.0 | | P4 | Tích hợp todaycode-be + CodeClash-fe | (repo consume) |

Cài & phát triển

"@amas-nghia/todaycode-missions": "^0.1.0",
"@amas-nghia/todaycode-game-engine": "^0.2.1"

Cần GITHUB_TOKEN (read:packages) + .npmrc scope @amas-nghia.

pnpm install && pnpm test && pnpm build && pnpm lint

Giữ thuần khiết (không I/O / Math.random / clock); mọi thay đổi src kèm fixture + pnpm build + commit dist/ + tag semver.