DEV Community

Charles Koffler
Charles Koffler

Posted on • Edited on

๐Ÿ Revisiting Snake in Java with Clprolf

What if writing a small game could prove that architecture can be both clean and alive?
Letโ€™s revisit the classic Snake game โ€” but built with Clprolf,
a paradigm that turns clarity into a coding language.


๐Ÿง  1. From OOP to Clarity-Oriented Programming

Clprolf isnโ€™t a framework. Itโ€™s a language layer + methodology
that builds architectural meaning into Java itself.

Annotation Role
@Agent Domain logic
@Worker Technical performer (I/O, UI, OS, rendering)

When you read Clprolf code, you see intent, not just syntax.


โš™๏ธ 2. The Architecture of the Snake Game

The game has five layers โ€” all explicit:

SnakeGameScene (Agent)
 โ”œโ”€โ”€ SnakeImpl (Agent)
 โ”œโ”€โ”€ FoodExpertImpl (Agent)
 โ”œโ”€โ”€ SnakeGameSceneRendererImpl (Worker)
 โ”œโ”€โ”€ SnakeWindowImpl (Agent)
 โ””โ”€โ”€ SnakeGamePanelImpl (Agent, Swing-based UI component)
Enter fullscreen mode Exit fullscreen mode

Each one knows exactly what it should know, and nothing more.

For instance, the FoodExpert agent handles food positions โ€”
but knows nothing about the UI, keyboard, or rendering:

@Agent
public class FoodExpertImpl implements FoodExpert {
    private SnakeGameScene scene;

    public void positionFood() {
        Random random = new Random();
        ...
        food.setType(random.nextBoolean() ? FoodType.APPLE : FoodType.ORANGE);
        foodList.add(food);
    }
}
Enter fullscreen mode Exit fullscreen mode

Meanwhile, the Worker handles technical events and visual updates:

@Worker
public class SnakeGameSceneRendererImpl implements SnakeGameSceneRenderer {
    private SnakeGameScene scene;

    public SnakeGameSceneRendererImpl( SnakeGameScene scene) {
        this.scene = scene;
        EventQueue.invokeLater(this); // Executed in AWT thread
    }

    @Override
    public void run() {
        window = new SnakeWindowImpl(this); // creates and starts rendering
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ” 3. Understanding the Flow of Life โ€” The Snake Logic

The magic happens in SnakeImpl.
It shows how Clprolf models living behavior:
sliding, growing, interacting โ€” without spaghetti code.

protected void continueSliding() {
    if (this.lastSlidingType == SlidingType.STOPPED) return;

    SnakeLink newHeadLink = computeHeadLink(this.links.get(0));
    checkCollisionsForNewHead(newHeadLink);

    Food foodAtNewHeadPlace = this.scene.getFoodExpert().getFoodAt(newHeadLink.x, newHeadLink.y);
    updateBodyForSliding(foodAtNewHeadPlace != null, newHeadLink);
}
Enter fullscreen mode Exit fullscreen mode

Each call represents an intention (โ€œcontinue slidingโ€, โ€œhandle foodโ€, โ€œgrow bodyโ€).
The structure itself communicates meaning.


๐ŸŽจ 4. Rendering Without Losing the Model

The UI never controls the game directly.
The window only refreshes every 20 ms โ€”
and triggers the next logic step inside the paint cycle.

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    drawSnakes(g);
    drawFood(g);

    // End of long actions โ€” one physics step every few frames
    this.gameWindow.getReal().getScene().getSnake().endLongActions();
    this.gameWindow.getReal().getScene().getSnake_two().endLongActions();
}
Enter fullscreen mode Exit fullscreen mode

So the render loop and game loop are naturally synchronized โ€”
without custom game threads or complex scheduling.


๐Ÿ’ก 5. What We Learn from This Example

  • You can build a complete game architecture without losing clarity.
  • Workers act as true performers, keeping the domain clean.
  • The render loop stays synchronous, transparent, and elegant.

The result? A Snake thatโ€™s both fun and architecturally explicit.


๐Ÿ Conclusion

We did not just implement Snake. We made its responsibilities visible: the scene owns the game state, agents express domain behavior, and workers perform technical execution.


Top comments (0)