显示 HN:Emacs Lisp 中的 Micropolis/SimCity 克隆
Show HN: Micropolis/SimCity Clone in Emacs Lisp

原始链接: https://github.com/vkazanov/elcity

## ElCity:一个在Emacs中实现的城市建造游戏 ElCity是一个回合制的城市建造游戏,完全在Emacs内部实现,使用优化的终端界面的ASCII界面。它的设计目的是展示“函数式核心/命令式外壳”架构——一个确定性的、纯粹的核心模拟处理逻辑,而UI管理渲染和输入。 玩家使用区域(住宅、商业、工业)、道路和发电厂建造城市,目标是发展人口和经济。关键机制包括区域增长的电力/道路邻近性,以及区域类型之间的资源依赖关系。 该游戏通过用于平铺定义的领域特定语言(DSL)和对纯函数的关注,优先考虑代码清晰度和可维护性。这种方法有助于调试、可扩展性和自动化测试。 要玩游戏,克隆仓库,将其添加到Emacs加载路径,并使用`elcity-start`启动。控制简单:箭头键用于移动,字母用于建造/拆除,'n'用于推进回合。

一位名为 vkazanov 的开发者用 Emacs Lisp 创建了一个 Micropolis/SimCity 克隆游戏,并在 Hacker News 上分享了它。该项目历时一周完成,既是一个有趣的模拟游戏,也是对软件架构的一次探索——特别是“函数式核心/命令式外壳”方法。 一个关键的成就是为定义图块和效果而创建的自定义领域特定语言 (DSL),这使得游戏易于扩展和测试。虽然目前游戏玩法比较简单,但开发者正在寻求反馈以改进模拟效果。 Hacker News 上的用户称赞了这个项目,强调了对更多 ASCII 游戏的需求,以及 Emacs 实现带来的额外优势。项目 README 中提供了截图,可在 GitHub 上找到。
相关文章

原文

ElCity is a small, turn-based city builder that runs entirely inside Emacs. The UI is ASCII-based and optimized for terminal Emacs sessions. The core simulation is deterministic and pure, while the UI handles rendering and input.

This is an excercise in implementing the “functional core / imperative shell” architecture in a moderately sized project that with a developed UI. Every tile type is defined through a DSL, with a strong separation between state and effects. Most functions in the core are either pure or pure-ish.

Benefits to this approach:

  • easy to debug
  • scalable in terms of code: reduced cognitive load on both people and LLMs
  • easy UX/UI as state is always localized
  • easy to extend (with some discipline)
  • easy to autotest
  • Emacs 30.1+
  • Optional: Eask for dependency management

Clone the repository and add it to your Emacs load path. Example with use-package:

(use-package elcity
  :load-path "/path/to/elcity"
  :commands (elcity-start))

If you are not using use-package, add the directory to load-path and require the entry point:

(add-to-list 'load-path "/path/to/elcity")
(require 'elcity)
(elcity-start)

From the project root:

Or from Emacs: M-x elcity-start

  • The game is turn-based. Press n to advance one turn.
  • Funds increase each turn by: (Population / 2) + (Commercial level + Industrial level).
  • City Hall is the source of road connectivity and is unique and non-demolishable.
  • Roads are only connected if they trace through other roads to City Hall.
  • Power plants provide a Manhattan-radius of 6 tiles.
  • Zones grow by 1 level per turn if powered and road-adjacent.
  • Zones decay by 1 level per turn if they lose power or road adjacency.
  • Maximum zone level is 3.
  • Residential (R) supplies Workers in a radius and dislikes Pollution.
  • Industrial (I) supplies Goods and Pollution and requires Workers.
  • Commercial (C) requires Workers and Goods.
  • R select Residential and place once
  • C select Commercial and place once
  • I select Industrial and place once
  • r select Road and place once
  • p select Power plant and place once
  • h select City Hall and place once
  • SPC or RET place selected tool at cursor
  • d demolish at cursor
  • u undo last action
  • n advance one turn
  • Arrow keys move the cursor
  • o cycle overlays (goods, polution, connectivity, etc)

This is a simplified snapshot to show the general layout.

Funds: 1000 | Pop: 0 | Income: 0 | Turn: 0 | Overlay: none | Tool: none | Unpowered: 0 | Disconnected: 0 | Polluted: 0
Cursor: (0,0) | Tile: HH City Hall | Level: 0 | Build: N | Demo: N | Unique: Y | Cost: 150 | Pop: 0 | Inc: 0
Legend: R res  C com  I ind  == road  Overlay: Pwr Conn Poll Work Goods
Keys: R/C/I zone (select tool) | r road | p power | h city hall | d demolish | n next turn
Place: SPC/RET place selected tool | u undo
Overlay: o cycle (none/power/connectivity/pollution/workers/goods)
Move: arrows
   00 01 02 03 04 05 06 07 08 09
   +--------------------+
00 |HH==R0..PP..........|
01 |....................|
02 |~~~~~~..............|
   +--------------------+
  • Start with a custom map by calling elcity-start with a list of row strings.
  • Example call: (elcity-start '("H=R0" "...."))
  • Map tokens are defined in tile definitions.
  • Canonical tokens include .., ~~, ==, PP, HH, R0-=R3=, C0-=C3=, I0-=I3=.
  • Short aliases are also accepted: ., ~, =, P, H, R, C, I.
  • Default map rows live in elcity-maps.el (elcity-map-default-rows).
  • Default map size is set by elcity-core-map-width and elcity-core-map-height.
  • make test runs ERT tests.
  • make lint runs package lint, checkdoc, and byte compilation.
  • make compile byte-compiles non-test files.
  • elcity.el entry point that wires core and UI
  • elcity-core.el pure simulation and state transitions
  • elcity-tiles.el tile definitions and effect metadata
  • elcity-ui.el UI shell and input handling
  • elcity-maps.el map presets
  • test/ ERT tests
联系我们 contact @ memedata.com