Some real practical example to teach object-oriented concepts and programming (in python)
I expect to update this a few times and hope to eventually have a long answer.
But let me start by explaining some things that you may already be aware of, but other readers may not.
First, OO programming is not, fundamentally, about inheritance and too many books and authors fail to understand that. Moreover, they use inheritance in a dreadful way that makes software hard to understand and harder to maintain.
For example, note that the Linnaeus style hierarchy of the biological world is almost entirely one of &quot;interfaces&quot; and not even &quot;abstract classes&quot;, much less concrete classes. There are no instantiated &quot;mammals&quot;, for example. It is only at the leave of the hierarchy that things actually exist, other than as ideas. There is some genetic continuity, of course.
Second, there are some principles that can guide you in writing and teaching OO design, but they require discipline. And part of that discipline is to control the situations in which you &quot;break&quot; the rules.
My first advice for anyone wanting to be an OO programmer is not to think in terms of inheritance, but, rather, of composition. Complex things (objects) are composed of other things (objects) that are a bit simpler than the containing object and provide it some essential service. If you write classes where all (or even most) of your instance variables are language primitives, then you don't really get it. And if those instance variables (objects or primitive) have a lot of getters and setters, then you aren't doing OO Programming at all.
In fact, making the above mistakes, requires that the programmer keep track of all details at all points of the program where OO is designed to capture decisions so that they needn't be &quot;checked&quot; again. Set it and forget it, so to speak.
So, if you want to build an automobile, don't think of it as a subclass of vehicle (which gains you nothing: a personal drone and a battleship are both vehicles). Think of it instead of being composed of various parts: engine, transmission, controls, accommodations, etc. And those parts are, themselves, composed of parts. An engine has igniters and pistons, exhaust, etc. Many of those are composed of parts also. It is only at the lowest, simplest level that you build with primitives.
Two of the principles that are worth keeping in mind and following almost always are the Liskov Substitution Principle and the Law of Demeter.
The first suggests that if you extend a class with a subclass you don't also extend the public interface of the subclass. Then all subclass objects are substitutable, differing in behavior but not in interface. Demeter, on the other hand, forces you to write more explicit code that makes relationships clear to a reader. Of course it also forces you to introduce more name, and if they are intention revealing names then your code is clearer.
The Liskov principle, of course is one of the elements of SOLID which you also need to incorporate into your thinking.
In my own programming I'm very faithful to Liskov, also defining Interfaces for most things before I write classes. I'm less faithful to Demeter in the heat of battle, cascading messages. But then I sometimes also need to unravel those a.b.c.d sorts of cascades to figure out what I really mean.
One goal I have in writing OO code is to seek to write only very short methods with a minimum of structure. In other words I try to minimize Cyclomatic Complexity. My palms start to get itchy after the fourth statement in a method of if the complexity level reaches three. I can't always get away with that, but it is a goal. The solution is to refactor complexity mercilessly. Factor out methods, of course, but also &quot;parts&quot;, creating new classes to manage the complexity. Even if many of those classes are Singletons the code is usually improved and having the goal in mind from the start, means that the refactoring step is less needed.
Design patters are tools that you need to be an effective programmer in most OO languages. Especially helpful ones are Strategy, Decorator, Observer, and Iterator. Most of these are actually used to build the various Java libraries.

Now, to get to the actual question asked here. But note that a lot of learning can take place even if the students never reach completion of the project in the allotted time. An agile approach (Extreme Programming, say, with you as &quot;Customer&quot;) to development leaves them with some functionality even if not all specifications are implemented.
Dungeon Game
Build a text based dungeon game. The main objects are characters (people), places, and things. The places are organized in some sort of map, maze, or grid. Things happen when characters enter places. Characters find and carry things. The things have actions, depending on the kind of thing. A &quot;spell&quot; is a &quot;thing&quot; whose action might depend on context. A &quot;transporter&quot; object might work differently in different rooms (strategy objects).
Note that the classic board game Chutes (or Snakes) and Ladders is a simplified version of this. A text based version avoids a lot of complexity.
Calculator
A calculator has parts such as keys and the display. Less visible are the internal memory, possibly a stack. Even the operations can be objects. The behavior of the keys changes, depending on the state of the computation (Strategy pattern). It is possible to build a simple calculator without a single IF statement, actually.
Abstract Computer with an Assembly language
A Stack Based computer processor simulation is pretty straightforward. There may be accumulators and such, but a single stack on which all operations are done is simple and complete. The operations can be objects (parts). One advantage of this example is that most of the necessary methods can be very short. A program can be read with a Java Scanner object. It needs a program counter at least and possibly a frame pointer if the language is to support subroutines.
Sticky Notes (I haven't tried this)
An application that lets users keep notes and cross reference and organize them. Some classes might be Notes, Keywords, Connections, Lists.
Jeopardy
A simulator for the jeopardy game from TV. Categories, Answers, Questions, Teams, Scores.
(Back soon, maybe).