- Game play is rich and complex, but intuitive. Rules make sense (especially if you catch the allusions to myth and modern storytelling) and actions have consequences. Almost any object or creature can and will interact with anything else.
- Intelligent humor makes the perverse and random ways to suffer and die (almost) bearable.
- The game is so challenging that even if I skim the spoilers and play with infinite lives, I can get myself into apparently inextricable situations. Yet, it's still enjoyable without cheats and spoilers.
- The display is stripped-down but suggestive. For example, line of sight and memory interact intuitively -- both are combined into one map, which lets you fit more of the map on one screen (unlike, say, a first-person shooter, which keeps the map separate from the view).
- Agents have limited information, and may even forget things.
- Things happen beyond agents' awareness.
- Attempted actions may not succeed: luck (which may improve with skill) plays a role. (Nethack, like most games, models luck probabilistically.)
- Actions usually change the world state irreversibly.
- Object interactions depend on the properties of all the objects involved. (In terms of object-oriented programming, your object system needs mixins.)
- Some items and creatures are unique and irreplaceable.
- Turn-based: there is no need to manage simultaneous attempts to change the world's state.
- Rule-based: interactions are modeled simply, with little resort to a priori physical modeling (e.g., Newton's laws). This means interactions are not usually computationally intensive.
- Very simple graphics.
The chosen programming model affects the teaching approach. For example, probabilistic success requires pseudorandom number generation, but if the programming model is functional, the novice's mental model ("rolling a die") differs from the usual stateful implementation. Also, the lessons learned at this stage may require correction when the model is generalized to handle real-time (instead of turn-based) interactions, since multiple agents will need to draw random numbers simultaneously (parallel pseudorandom number generation). In addition, the programming language's version of OOP may make it more or less difficult to explain how to implement object interactions. Some (such as Common Lisp) handle mixins trivially, whereas others (Java, C++) do not. Reliance on "design patterns" to cover the programming language's deficiencies can help students deal with languages used in industry, but may also limit their flexibility with programming languages and models. This doesn't mean a dogmatic insistence on "the one true programming language." It's better to understand the deficiencies of one's chosen language, and learn how to work around them, than not to recognize deficiencies at all.
Nethack offers another useful pedagogical feature: it's well-crafted and balanced. Playing it teaches students that making an application good comes not so much from learning new programming tricks, as from careful and laborious design and testing. "Testing" here means both correctness ("It didn't crash"), which students experience by necessity, as well as user experience testing ("It's fun to play"), which few students experience much in an undergraduate computer science curriculum.