Game Development 15 min read

How to Recreate the Viral ‘Sheep a Sheep’ Puzzle Game in Godot

This article walks through recreating the popular ‘Sheep a Sheep’ puzzle game using Godot Engine, detailing the game’s mechanics, three stack patterns, data structures, detection of selectable tiles, level generation, shuffling, mask handling, and inter‑object communication, while sharing code snippets and design insights.

Programmer DD
Programmer DD
Programmer DD
How to Recreate the Viral ‘Sheep a Sheep’ Puzzle Game in Godot

Introduction

Yesterday a friend asked me to clone the viral game "Sheep a Sheep" because it is notoriously hard. I have not played the original, but I will attempt a remake using Godot Engine. The project is open‑source on GitCode.

Gameplay Overview

The game resembles classic tile‑matching titles such as LianLianKan and is often compared to 3tiles . It is a low‑complexity casual puzzle, but the second level has an extremely low pass rate, which sparked widespread discussion.

Implementation Overview

The overall implementation is simple, yet three key aspects require attention:

Design of the stack (card pile) data structure.

Detection and updating of selectable ("window") cards.

A "window card" is a card that can currently be picked from a stack.

Stack Structure and Data Model

The stack consists of three pattern types (A, B, C) that can be combined to form any level layout. Each pattern is essentially a three‑dimensional array.

Pattern A (blue circle): a card covers exactly one card below it; when the upper card is removed, the lower card becomes a window card.

Pattern C (red circle): a card can cover up to four cards below it; a card becomes a window card only when all four covering cards are removed.

Pattern B (implied): a card covers two cards below it; similar logic applies.

All three patterns can be represented as a 3‑D array where the x, y, and z dimensions correspond to width, height, and depth.

Below are visual illustrations of the three patterns:

Base Container Class (GDScript)

#MContainerBase
extends Node2D
class_name MContainerBase

func _ready():
    add_to_group(name)
    add_to_group("game")
    var Mask = FileReader.read(mask_file, null)
    box.resize(size_x)
    for i in range(size_x):
        box[i] = []
        box[i].resize(size_y)
        for j in range(size_y):
            box[i][j] = []
            box[i][j].resize(size_z)
            for k in range(size_z):
                if Mask == null or Mask[i][j] == 1:
                    box[i][j][k] = add_tile(i, j, k, get_parent().distribute_face())
                else:
                    box[i][j][k] = null
    for x in range(size_x):
        for y in range(size_y):
            for z in range(size_z):
                check_is_on_top(x, y, z)

The basic stack is a three‑dimensional array (x * y * z) that can be shaped into columns, rows, or pyramids without affecting later logic.

Mask Definition

A mask array defines which positions contain tiles, allowing custom shapes such as the "S" pattern used for the CSDN logo.

# S形遮罩
[
    [0,0,0,0,0],
    [0,0,0,0,0],
    [1,1,1,0,1],
    [1,0,1,0,1],
    [1,0,1,1,1]
]

Detecting Window Cards

Each stack pattern derives from MContainerBase and implements its own detection logic.

Pattern A – Single Cover

#1 Cover 1
extends MContainerBase

func check_is_on_top(x, y, z):
    if has_tile(x, y, z):
        if not has_tile(x, y, z + 1):
            (box[x][y][z] as MTile).set_is_on_top(true)

Pattern B – Double Cover

#1 Cover 2
extends MContainerBase

func check_is_on_top(x, y, z):
    if has_tile(x, y, z):
        if z % 2 == 0:
            if not has_tile(x, y, z + 1) and not has_tile(x - 1, y, z + 1):
                (box[x][y][z] as MTile).set_is_on_top(true)
        else:
            if not has_tile(x, y, z + 1) and not has_tile(x + 1, y, z + 1):
                (box[x][y][z] as MTile).set_is_on_top(true)

Pattern C – Quad Cover

#1 Cover 4
extends MContainerBase

func check_is_on_top(x, y, z):
    if has_tile(x, y, z):
        if z % 2 == 0:
            if not has_tile(x, y, z + 1) and not has_tile(x - 1, y, z + 1) and not has_tile(x, y - 1, z + 1) and not has_tile(x - 1, y - 1, z + 1):
                (box[x][y][z] as MTile).set_is_on_top(true)
        else:
            if not has_tile(x, y, z + 1) and not has_tile(x + 1, y, z + 1) and not has_tile(x, y + 1, z + 1) and not has_tile(x + 1, y + 1, z + 1):
                (box[x][y][z] as MTile).set_is_on_top(true)

Level Generation

Each level must contain a multiple of three of every tile type. The following script builds a pool of tiles, shuffles it, and uses it to populate the board.

var tiles = []
export var initial_tiles = {
    0:10, 1:10, 2:10, 3:10, 4:10, 5:10, 6:10, 7:10, 8:10, 9:10,
    10:10, 11:10, 12:10, 13:10, 14:10, 15:10
}

func _init():
    for key in initial_tiles:
        var num = initial_tiles[key] * 3
        for i in range(0, num):
            tiles.append(key)
    tiles.shuffle()

The dictionary keys represent tile patterns; the values indicate how many groups of three appear in the level. After populating the pool, the array is shuffled to randomize tile placement.

Shuffling Tool

func shuffle_tiles():
    tiles.shuffle()
    tiles_index = -1

func redistribute_face() -> int:
    tiles_index += 1
    return tiles[tiles_index]

When the player triggers a shuffle, the current board tiles are recorded, the array is shuffled, and each board position receives a new tile value.

Mask File Reading

class_name FileReader

static func read(path, default_data):
    var data = default_data
    var file = File.new()
    file.open(path, File.READ)
    var content :String = file.get_as_text()
    if not content.empty():
        data = str2var(content)
    file.close()
    return data

Godot’s str2var conveniently converts a string representation of a mask into a usable array.

Object Communication

The game relies heavily on Godot’s group system for communication between tiles, stacks, and levels. This mechanism allows any node to broadcast or listen for events without tight coupling.

Conclusion

Recreating the "Sheep a Sheep" puzzle in Godot is technically straightforward; however, the game’s intentional design quirks—such as hidden dead‑ends and strict tile‑count constraints—turned its flaws into a viral hook, demonstrating how gameplay mechanics can become a marketing advantage.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

game developmentData StructuresLevel DesignPuzzle GameGDScriptGodot
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.