How to Make Mini Othello (vs. AI), Part 1

How to Make Mini Othello (vs. AI), Part 1
ok-scratch
Click the green flag to lay out cloned board tiles that light up when you can place a disc. Learn how an 8-direction scan flips discs and how the CPU opponent prioritizes the corners.

So, what are we building in Scratch?

The project this tutorial is based on

オセロ入門

オセロ入門

by ok-scratch
Play it first Play it first
Here is the project we are working from. Looping through all 8 directions with a single offset array is a slick way to grab every disc you can flip. The CPU runs the same logic to score each move, then piles on a +100 bonus for corner squares, so even a tiny 4x4 board turns into a real tactical showdown. No stacks of if-else branches, just numeric scoring driving the whole strategy. Let's see how it's built.

What you'll build

Create three sprites, Judge, Tile, and Start Button, and use clones to render the 4x4 board. Implement the core rule of placing a disc and flipping the ones it traps, plus a CPU opponent that prioritizes the corners.

#1Judge: Getting the Judge ready to start

ok-scratch ok-scratch
Let's begin with the "Judge", the sprite that runs the whole game. It's the command center that handles everything in Mini Reversi—moving the match along and deciding who wins.

Setup

Open the "Judge" sprite

JudgeJudge
About this sprite
The command-center sprite that runs the whole game, manages the board, and decides the winner.
What it does
We'll build the judge that manages the rules of mini Reversi. It tracks the game state and whose turn it is, and runs the match between the player and the CPU.

Build

step-0

It starts when the flag is clicked with Eventswhen greenflag clicked. We switch the backdrop to the chalkboard and place it at a smallish size near the top-right of the screen.

Finally we make it appear with Looksshow. For now we're just tidying up its look—the game rules come next.

Check your progress Check your progress
Press the flag and the referee cat pops up over on the right, then the backdrop switches to a chalkboard. This is our star making an entrance, and we're setting its position and size right here too.

#2Cell: Initializing the cell

ok-scratch ok-scratch
Now that the Judge's foundation is done, let's build the board's "Cell" next. The plan is to multiply this cell and lay out the board.

Setup

Open the "Cell" sprite

CellCell
About this sprite
The sprite that represents one cell on the board and switches between stone colors and the hint display.
What it does
We'll clone 16 board cells and line them up. When a stone is placed the cell changes color, and playable cells light up as a hint.

Add the "Cell ID" variable

The cell number assigned to this clone.

Add the

Build

step-1

When the flag is clicked, we hide the original for now with Lookshide. We set "Cell ID" to 0 and reset the graphic effects too.

The original is only the source for the clones, so it never shows on screen. What actually lines up on the board are the clones we'll make later.

Check your progress Check your progress
The square's main sprite gets hidden and reset on the flag, while the Start button stands by in the bottom-right. It's all the prep work getting done before the player clicks anything.

#3Start Button: Placing the button

ok-scratch ok-scratch
With the cell ready, it's time for the "Start Button" that begins the game. We'll make the thing that kicks off a match when you press it.

Setup

Open the "Start Button" sprite

Start ButtonStart Button
About this sprite
The button sprite that controls starting the game.
What it does
We'll build a start button that begins the game when pressed. It hides during the game and shows again when it ends.

Build

step-2

It starts on the flag with Eventswhen greenflag clicked. We switch to the button costume and put it just below the Judge.

Check your progress Check your progress
The Start button we set up earlier finally shows up on screen. We clear the graphic effects and display it, so now it's ready to be clicked.

#4Start Button: Showing the button

ok-scratch ok-scratch
That button so far only has its position set. Here we go all the way to actually putting it on screen.
step-3

After resetting the effects, we show it with Looksshow. Now the start button is ready to be pressed.

Check your progress Check your progress
The moment you press the flag, we set up the direction list and the board data, count the pieces, and show the blue and pink totals on screen. All the behind-the-scenes prep kicks in at once.

#5Judge: Initializing the game state

ok-scratch ok-scratch
The looks team is done, so let's head back to the Judge and set up the game's "state". This is where rule-building really begins.

Setup

Open the "Judge" sprite

Judge
Judge

Add the "Game State" variable

A variable that tracks the game's progress (0 = title, 1 = playing, 2 = over).

Add the

Add the "Turn" variable

A variable that tracks whose turn it is (1 = the blue player, 2 = the pink CPU).

Add the

Add the "Move Done" variable

A variable that shows whether the player has finished their move.

Add the

Add the "Pass Count" variable

A variable that counts how many passes have happened in a row.

Add the

Add the "Clicked Spot" variable

A variable that holds the number of the cell that was clicked.

Add the

Build

step-4

With Variablesset ( ) to ( ) we set "Game State" to 0 (the title screen). We line up initial values like turn = 1 so the blue player goes first.

"Move Done", "Pass Count", and "Clicked Spot" all go to 0 too. We manage the flow of the game with numbers, and sprites all over the place watch these numbers to decide what to do.

Check your progress Check your progress
At the end of the flag script, we broadcast the signals to build the squares and show the buttons, and the referee lays down the rules: blue is you, pink is me.

#6Judge: Preparing the direction list

ok-scratch ok-scratch
Here's a slightly fun bit of prep. We'll set up the "directions" used when flipping stones as a list of numbers.

Setup

Add the "_prepare lists" custom block

Sets up the directions list and the corner spots list.

Add the

Add the "Directions" list

A list of movement amounts used to check all 8 directions on the board.

Add the

Build

step-5

With My Blocksdefine ( ) we make a custom block called "_Set Up Lists". We empty out "Directions" for now and add -7, -6, -5.

These numbers stand for "how far one step moves" on the board. Because we hold the board as a single list, a direction can be expressed with just one number. It'll make sense when we build the board.

Check your progress Check your progress
Catching the build-the-squares signal, a 4×4 loop spawns 16 clones. The factory sprite even has a guard so it doesn't clone itself.

#7Judge: Completing all 8 directions

ok-scratch ok-scratch
Continuing from before, we add the rest of the directions. We add -1, 1, 5, 6, 7 to "Directions".
step-6

That makes 8 in total. Up-down, left-right, and diagonal—every direction is now covered by a single number each.

For example, 1 means one cell to the right, 6 means one cell down, and 7 means a diagonal step to the lower-right. Once directions are gathered in a list, we can check every direction later just by looping 8 times.

Check your progress Check your progress
Each clone starts up and reads the square-position list to learn which square it's in charge of. It's the first step toward every square knowing its own spot.

#8Judge: Registering the corner cells

ok-scratch ok-scratch
Next we memorize where the board's "corners" are. We empty "Corner Cells" and add 8, 11, 26, 29.

Setup

Add the "Corner Spots" list

A list of the cell numbers at the corners of the board.

Add the

Build

step-7

In Reversi the corners are incredibly strong cells. Later the computer uses this list to decide to "aim for the corners first".

Check your progress Check your progress
The clones line up and appear at their board positions. When a square's state changes, it briefly grows to 150 and then eases back to 110 for a little bouncy effect.

#9Judge: Making the board container

Setup

Add the "_build board" custom block

Builds the board and sets the starting layout.

Add the

Add the "Board" list

A list that holds the state of all 36 cells on the board.

Add the

Add the "Cell Numbers" list

A list of the 16 playable cell numbers on the board.

Add the

Build

step-8

From here we make the "_Build Board" block that creates the board itself. First we empty "Board", then with Controlrepeat ( ) we add the number 9 thirty-six times.

The board we play on is 4×4, so why 36 cells (6×6)? It's actually to wrap a "wall" all the way around the outside. This 9 is the mark for a wall.

By filling the outer ring with walls, a line scanning for stones naturally stops the moment it steps off the board. That saves us from checking "did we go out of bounds?" every time—a clever technique called a sentinel. We also empty "Cell Numbers" here.

Check your progress Check your progress
If a square's state is 1 it switches to the blue-piece costume, if it's 2 the pink one, then sets ghost to 0 for a crisp look. This is where the piece colors show up on screen.

#10Judge: Looping over rows and columns

ok-scratch ok-scratch
Onto the empty board, we write in the 16 playable cell positions. We start by setting "Row Counter" to 1.

Setup

Add the "Row Counter" variable

The row counter used while building the board.

Add the

Add the "Column Counter" variable

The column counter used while building the board.

Add the

Build

step-9

With Controlrepeat ( ) we loop for the 4 vertical rows, and inside it we reset "Column Counter" to 1. With this double loop of rows and columns, we process the 4×4 cells in order.

Check your progress Check your progress
Out of the empty squares, only the ones you can play right now get checked against the hint list and glow semi-transparent. The light shows you where you can move—the heart of the hint display.

#11Judge: Calculating cell numbers

step-10

In the inner loop, we calculate each cell's "number". We spin 4 columns across with Controlrepeat ( ).

The number comes from "row × 6 + column + 1". We add this to "Cell Numbers" and rewrite the "Board" at that spot to 0 (empty).

Even with a single list, combining multiplication and addition lets us represent 2D coordinates. Once the calculation is done, we add 1 to "Column Counter" and move to the next cell.

Check your progress Check your progress
Empty squares you can't play get shown faintly so they stand apart. We also give the button a way to catch a show signal, so it can appear whenever it's needed.

#12Judge: On to the next row

ok-scratch ok-scratch
Once we've written a full row of cells across, we add 1 to "Row Counter". That moves us down one row.
step-11

Repeating this sets a number and an empty state on all 16 cells. It's like the outer part of the double loop advancing one lap.

Check your progress Check your progress
This builds the reaction to clicking the Start button. If a game isn't running, it plays the Coin sound and pops the button up to 130. It's the touch that gives your click some feedback.

#13Judge: Placing the first stones

ok-scratch ok-scratch
With the board ready, we place Reversi's classic "four stones in the middle". We rewrite the 15th slot of "Board" to 2 (pink) and the 16th to 1 (blue).
step-12

These two, plus two more in the next step, make the diagonal pattern in the center. It becomes the standard shape at the start of a game.

Check your progress Check your progress
The enlarged button shrinks back to size, hides, and broadcasts the start-the-game signal. Click, shrink, start—the whole flow links up into one line.

#14Judge: Finishing the starting layout

ok-scratch ok-scratch
We place the remaining two center cells too. We rewrite the 21st slot to 1 (blue) and the 22nd to 2 (pink).

Setup

Add the "Stones to Flip" list

A list of the cells to flip when a stone is placed.

Add the

Add the "Playable Spots" list

A list of the cell numbers where a stone can currently be placed.

Add the

Build

step-13

Now blue and pink each have two stones diagonally facing each other—the Reversi-style starting shape is complete.

Finally we empty and reset "Flip List" and "Playable Cells". That's cleanup so the previous state isn't carried over into the next game.

Check your progress Check your progress
On the start signal, the board gets rebuilt, the turn and state reset, and we jump into match mode. Meanwhile the button catches a hide signal and vanishes from the screen.

#15Judge: Getting ready to count stones

ok-scratch ok-scratch
We make the "_Count Stones" block that counts the stones on the board. This tells us how many each side currently has.

Setup

Add the "_count stones" custom block

Counts the number of blue and pink stones.

Add the

Add the "Blue Count" variable

The number of blue stones on the board.

Add the

Add the "Pink Count" variable

The number of pink stones on the board.

Add the

Add the "Count Index" variable

The loop index used to count stones.

Add the

Build

step-14

We reset "Blue Count" and "Pink Count" to 0 for now. "Count Number", which marks the position we're counting, also starts from 1.

#16Judge: Counting the blue stones

Setup

Add the "Spot to Count" variable

The cell number whose stone is being counted.

Add the

Build

step-15

With Controlrepeat ( ) we loop over the 16 cells, checking the contents one cell at a time.

We take the number of the cell we're looking at from "Cell Numbers", and if its "Board" value is 1 (blue), we add 1 to "Blue Count" with Variableschange ( ) by ( ).

#17Judge: Counting the pink stones

ok-scratch ok-scratch
We check the same cell for pink too. If "Board" is 2, we add 1 to the pink count.
step-16

Once we've checked, we advance "Count Number" by 1 and move to the next cell. Going through all 16 cells gives us the totals for both colors.

#18Judge: Bundling the initialization

step-17

We call the prep blocks we've built all together. With My Blocks( ) we run "_Set Up Lists" → "_Build Board" → "_Count Stones" in order.

This order quietly matters. We can't count stones unless we've prepared the directions and the board first.

Finally we show "Blue Count" and "Pink Count" on screen. That keeps the score visible throughout the match.

#19Judge: Sending the start signal

ok-scratch ok-scratch
This wraps up the Judge's initialization. We fire a "get ready" signal to the other sprites.

Setup

Add the "Setup Cells" message

A message that tells the cells to set themselves up.

Add the

Add the "Show Button" message

A message that shows the start button.

Add the

Build

step-18

With Eventsbroadcast ( ) we send "Set Up Cells" and "Show Button". Lining up the cells and showing the button are handled by whoever receives the signal.

Finally, with Lookssay ( ) we greet the player with the rules, introducing the opponent with something like "Blue is you, pink is me."

#20Cell: Starting to spawn cells

ok-scratch ok-scratch
The Judge's initialization is done, so now it's the Cell's turn. From here we lay out the board's 16 cells as clones.

Setup

Open the "Cell" sprite

Cell
Cell

Add the "Placement Row" variable

The row position used when arranging the clones.

Add the

Build

step-19

It springs into action when it receives "Set Up Cells" via Eventswhen I receive ( ). But when "Cell ID" is greater than 0, we halt it with Controlstop.

This is a stopper that prevents clones from also receiving the signal and multiplying out of control. Only the original does the laying-out work—that's the split of duties.

#21Cell: The row loop for laying out

ok-scratch ok-scratch
To lay out the cells in a grid, we build a double loop of rows and columns. We start by setting "Place Row" to 1.

Setup

Add the "Placement Column" variable

The column position used when arranging the clones.

Add the

Build

step-20

With Controlrepeat ( ) we spin the 4 vertical rows, and inside it we reset "Place Column" to 1 each time. It's the same double-loop shape as when we built the board.

#22Cell: Cloning the cells

step-21

In the inner loop, we actually make the cell clones. We spin 4 columns across with Controlrepeat ( ).

We add 1 to "Cell ID", then create a clone of ourselves with Controlcreate clone of ( ). Clones are born one by one, each with a serial number.

After making one, we advance "Place Column" by 1 and move to the next. Repeating this lines up 4 cells per row.

#23Cell: On to the next row's cells

ok-scratch ok-scratch
Once we've finished making a row of cells, we add 1 to "Place Row". That moves us to making the row one step down.
step-22

When the outer loop runs 4 laps, we get 16 cells in total, 4×4.

#24Cell: Resetting the original's number

ok-scratch ok-scratch
Once all the clones are made, we set the original's "Cell ID" back to 0.
step-23

This keeps the original as "ID 0 = the layout role". The clones numbered 1 to 16 are the ones that actually light up on the board—that division of roles is preserved.

#25Cell: Waking up the clones

Setup

Add the "My Spot Number" variable

The board cell number that this clone corresponds to.

Add the

Build

step-24

From here we build what each newly born clone does. It starts the moment it wakes up as a clone with Controlwhen I start as a clone.

First, using its own "Cell ID", it pulls its assigned cell from "Cell Numbers" and records it in "My Spot". Since each clone holds a different number, they can each take charge of a different cell.

#26Cell: Placing the cell and showing it

Setup

Add the "Last Value" variable

The state of this cell the last time it was checked.

Add the

Build

step-25

Once its assignment is set, it moves to that spot on screen. It calculates coordinates from "Place Column" and "Place Row" and drops right into place with Motiongo to x: ( ) y: ( ).

We set the size to 110 and set "Last State" to -1. That's the mark for "haven't looked even once yet." When it's ready, we show it with Looksshow.

#27Cell: Watching the board

Setup

Add the "Now Value" variable

The state of this cell being checked right now.

Add the

Build

step-26

This is the heart of each cell. With Controlforever it keeps watching its own assigned cell forever.

Every time, it reads its cell's contents from "Board" and puts them into "Current State". Whether a stone was placed or it's empty, it receives that in real time.

The Judge just rewrites the board list, and each cell goes and matches its own look on its own. No need to send commands one at a time—it's a clever design.

#28Cell: Growing when a stone changes

step-27

Only the instant a cell's state differs from last time, we add an effect. With Controlif ( ) then we check whether "Current State" and "Last State" differ.

If they differ, we update the record and pop the size up to 150. The moment a stone is placed, it puffs up big.

After that, while the size is bigger than 110, we shrink it little by little by -6. Grow, then gradually shrink—that makes an anime-like motion.

#29Cell: Showing the blue stone

step-28

We switch the look based on what we watched. If "Current State" is 1 (blue), we change to the blue stone costume with Looksswitch costume to ( ).

We set the ghost effect to 0 to show it clearly. Now a cell where blue was placed really looks like a blue stone.

#30Cell: Showing the pink stone

ok-scratch ok-scratch
Same vibe for pink. If "Current State" is 2, we switch to the pink stone costume.
step-29

This one's crisp at ghost effect 0 too. It's built just like the blue one, so it's like a clone in a different color.

#31Cell: Lighting up the playable cells

step-30

For an empty cell (state 0), we do something a little clever. With Controlif ( ) then we check whether we're in "Playable Cells".

If we are, that's the signal for "you can place here now." We switch to the hint costume and light it faintly by setting the ghost effect to 20.

#32Cell: Dimming the empty cells

ok-scratch ok-scratch
Conversely, empty cells you can't play show up modestly. We switch to the empty-cell costume and apply a ghost effect up to 65.
step-31

That's pretty see-through, so it blends into the board's background. Only the playable cells stand out, so you can tell where to play at a glance.

#33Start Button: Re-showing the button

ok-scratch ok-scratch
The cells display, so let's return to the start button. We build the mechanism that shows the button on the Judge's signal.

Setup

Open the "Start Button" sprite

Start Button
Start Button

Build

step-32

When it receives "Show Button" via Eventswhen I receive ( ), it sets the size to 100 and shows it with Looksshow. Before the game starts or after a reset, it becomes pressable again.

#34Start Button: When the button is pressed

step-33

We build the reaction for when the button is pressed. We catch the click with Eventswhen this sprite clicked.

But with Controlif ( ) then it only reacts when "Game State" is not 1 (in a match). That's a guard so it won't start if it's accidentally pressed during a match.

If it's OK, it plays the "Coin" sound and pops the size up to 130. That's an effect to give a sense of "press".

#35Start Button: Sending the game-start signal

ok-scratch ok-scratch
Continuing the press effect. We wait just 0.08 seconds and return the size to 100. In that instant, the button looks like it got pushed in.

Setup

Add the "Game Start" message

A message that tells the Judge the game has started.

Add the

Build

step-34

After that we hide the button with Lookshide and send "Start Game" with Eventsbroadcast ( ). From there, the Judge that receives it sets up the match.

#36Judge: Setting up the match

Setup

Open the "Judge" sprite

Judge
Judge

Add the "Hide Button" message

A message that hides the start button.

Add the

Build

step-35

With the button handled, next we return to the Judge. When the signal arrives, the Judge gets the match ready. It starts by receiving "Start Game" via Eventswhen I receive ( ).

It wipes the board clean with "_Build Board", sets the turn to 1 (blue), and resets the pass count and move-done to 0. Then it sets "Game State" to 1 to switch into match mode.

It recounts the stones and sends "Hide Button" with Eventsbroadcast ( ). This is what lets you restart as many times as you like.

#37Start Button: Hiding the button

Setup

Open the "Start Button" sprite

Start Button
Start Button

Build

step-36

The Judge is prepped, so next we go back to the button side. When the "hide" signal comes, the button slips away. It receives "Hide Button" via Eventswhen I receive ( ).

Its simple job is just to hide with Lookshide. It disappears so it won't be in the way during the match—a thoughtful touch.

#38Judge: Finding stones to flip

ok-scratch ok-scratch
With the button area done, we return to the Judge. Now for the core of Reversi—the check that "flips the stones you sandwiched." This is the inside of the "_Check Flippable Stones" block.

Setup

Open the "Judge" sprite

Judge
Judge

Add the "_check flippable stones" custom block

Checks which stones can be flipped if a stone is placed on the given cell, and adds them to Stones to Flip.

Add the

Add the "Enemy Color" variable

The opponent's color, used when checking which stones to flip.

Add the

Add the "Direction Index" variable

The loop index used to check all 8 directions.

Add the

Build

step-37

It runs on a "cell number" and "placing color" it receives. First we empty "Flip List", and with Controlif ( ) then we only investigate when that cell is empty (0).

We get the "Enemy Color" from "3 - placing color". Since blue is 1 and pink is 2, subtracting from 3 gives the other one—a neat little trick. We also set the number that traces a direction to 1.

#39Judge: Checking all 8 directions

Setup

Add the "Step" variable

The amount of movement for one step in the direction being checked.

Add the

Add the "Scan Position" variable

The position being scanned while checking whether stones can be flipped.

Add the

Add the "Stones Being Checked" list

A list that temporarily holds the stones being checked to see if they can be flipped.

Add the

Build

step-38

Here the direction list really shows its worth. With Controlrepeat ( ) we loop 8 times, investigating the 8 directions in order.

Using "Direction Number", we take this round's move amount from "Directions" and set "Scan Position" to the spot one step forward from the placed cell. We also empty "Scanning Stones", which holds the stones under investigation.

ok-scratch ok-scratch
This "make directions a list of numbers and loop 8 times" approach is super clever. Written normally, you'd end up copy-pasting 8 conditions for up, down, left, right, and 4 diagonals. But this project holds the board as a single list, so "one cell to the lower-right" can be expressed as a single number like "+7". Just loop over a list of those 8 numbers, and you can check every direction with the same processing. Gathering directions into data and unifying the processing is a way of thinking the pros use too.

#40Judge: Counting the opponent's stones

step-39

We go straight in the chosen direction as long as the opponent's stones continue. With Controlrepeat until ( ) we repeat until "Scan Position" is no longer the enemy color.

Each time we find an opponent's stone, we note its spot in "Scanning Stones" and take another step in the same direction. Even if we go off the board here, the outer ring is a wall (9), so it won't match the enemy color and we stop naturally.

#41Judge: Confirming when we can sandwich

step-40

If the spot past the traced opponent stones is our own color, the sandwich is valid. With Controlif ( ) then we check whether "Scan Position" equals the "placing color".

If it's valid, we move all the stones we just noted into "Flip List". That confirms the stones that flip in this direction.

You can only flip when you sandwich the opponent and close it off with your own color—that's the rule of Reversi itself. Finally we advance the direction number by 1 to the next direction. Once all 8 directions are done, this block is complete.

#42Judge: Finding the playable cells

ok-scratch ok-scratch
Using that check from before, we list out "where you can place right now" completely. This is the inside of the "_Update Playable Cells" block.

Setup

Add the "_update playable spots" custom block

Checks which cells can currently be played and updates Playable Spots.

Add the

Add the "Hint Check Index" variable

The loop index used to check which cells can be played.

Add the

Add the "Spot to Check" variable

The candidate cell number being checked for a legal move.

Add the

Build

step-41

We empty "Playable Cells" and loop over the 16 cells with Controlrepeat ( ). For each cell, we call "_Check Flippable Stones" and try it with the current turn.

If the resulting "Flip List" has even one stone, that spot is playable. We confirm with Controlif ( ) then and add it to "Playable Cells". The hints that lit up the cells earlier were watching this list.

#43Cell: Accepting cell clicks

ok-scratch ok-scratch
With the judgment logic done, we let the player press the cells. We go back to the Cell side and build click handling.

Setup

Open the "Cell" sprite

Cell
Cell

Build

step-42

We catch the click with Eventswhen this sprite clicked. But the original with "Cell ID" 0 is ignored with Controlstop. Only the clones lined up on the board respond.

#44Cell: Checking the conditions to play

step-43

Even when clicked, you can't always place. With Controlif ( ) then we narrow the conditions.

It only accepts when "Game State" is 1 (in a match) and "Turn" is 1 (the blue player). We judge whether both conditions hold at once with Operators( ) and ( ). It's a guard so the computer's turn can't be hijacked.

#45Cell: Telling the Judge about the click

ok-scratch ok-scratch
Once the conditions are cleared, we tell the Judge which cell was pressed. We write our own cell number into "Clicked Spot".

Setup

Add the "Cell Clicked" message

A message that tells the Judge that a cell was clicked.

Add the

Build

step-44

After that we send "Cell Clicked" with Eventsbroadcast ( ). From there the Judge looks at this number and carries out placing the stone. The cell does the pressing, the Judge does the deciding—that's the teamwork.

Wrap-up

You should now be comfortable representing a board as a 1D list and handling all 8 directions at once with an offset array. Using a sentinel value to skip boundary checks is a quietly powerful trick too. The CPU's scoring logic carries over to other board games, so try applying it in your own projects.

Thank you for reading! Thank you for reading!
Bookmark and share this article, if you like.