Writing a Capture the Flag Bot in Minecraft

Aaron Vontell
AI and Games — By Regression Games
8 min readMar 10, 2023

--

Regression Games has announced our newest game mode and tournament, the Alpha Cup, sponsored by Steamship, which features a Capture the Flag game in Minecraft. In this tutorial, we will write a simple bot that reacts to events within the game to capture the flag and score it within your team’s base! Guides are available for Typescript and JavaScript (Python coming soon). If you don’t have a Replit account, you can clone the guides directly from GitHub (JS, TS), or follow along below.

Make sure to sign up at https://regression.gg/alpha-cup

About the Game Mode

The Capture the Flag game takes place on Arctic Algorithm Field. The map has a Blue Base and a Red Base, where teams spawn and return the flag for points.

Each team consists of three bots, which must work together to capture the white flag in the middle of the map. Teams score points by grabbing the flag, killing opponents, and scoring the flag. More specifically, the score values and win conditions are as follows:

  • Killing a player on the opposing team awards 1 point to your team. If the killed player was carrying the flag, 3 points are awarded instead.
  • 2 points are awarded for picking up a neutral or enemy-team flag.
  • 10 points are awarded for capturing the flag.
  • Win condition: The first team to reach 10 flag captures wins. If the match-time expires (limit at 10 minutes), then the team with the most captures wins. If both teams are tied for captures, then the team with the higher score wins.

During the course of the match, items will spawn at various item spawners on the map, located at the bases, middle of the map, and within the Sub Arctic Tunnel. These items include objects like potions, bows and arrows, swords, armor, and dirt blocks. For the full list and rates of items that can spawn, please see the Match Specification. Explore the map and develop strategies around its features to win!

Getting Started

Players can start on Regression Games by completing the following steps. Message us on our Discord if you get stuck!

  • Create an account on GitHub
  • Create an account on Regression Games and connect both your GitHub account and your Minecraft username
  • Download the Minecraft Launcher, and install + run Minecraft Java Edition 1.18.2 (please note that this is not the latest version! You can install specific versions by visiting the Installations tab and searching from 1.18.2)

Then, you can do one of three things to get started quickly:

  • Create a new Replit project from our templates: TypeScript | JavaScript
  • Clone our getting started guide directly from GitHub: TypeScript | JavaScriptopen the .tutorial folder for the guide.
  • Create a bot from a template within Regression Games, by going to Bot Manager, clicking “Create Bot” selecting your language, and then clicking the created Repository. You can learn more about how to edit your new bot from our docs.

These existing codebases will implement the algorithm below — we recommend following along in the guides, but you can read below to get a quick overview!

Once you create your initial project/bot, get into a game by clicking on Play > Capture the Flag > Solo. Select your bot from the dropdown list, and then queue up for a match!

Overview of our Algorithm

Our simplest bot will start with the following algorithm (and we will extend it later as well):

  1. When the match starts, wait for you (as a spectator) to type “start” into the chat before doing anything
  2. Then, the bot approaches the flag
  3. When the flag is obtained by the bot, the bot runs back to the scoring area
  4. The bot waits for the flag to spawn again, and once it does, it repeats steps 2–4.

Our starting code implements this entirely for you! Here is the example for TypeScript, but you can see our JavaScript guide as well.

import { RGBot } from "rg-bot";
import RGCTFUtils, { CTFEvent } from "rg-ctf-utils";
import { Vec3 } from "vec3";

/**
* This strategy is the simplest example of how to get started
* with the rg-bot and rg-ctf-utils packages. The Bot will get
* the flag and then run back to base to score.
*
* rg-bot docs: https://github.com/Regression-Games/RegressionBot/blob/main/docs/api.md
* rg-ctf-utils docs: https://github.com/Regression-Games/rg-ctf-utils
*/
export function configureBot(bot: RGBot) {

// Since most blocks can't be broken on Arctic Algorithm Field,
// don't allow digging while pathfinding
bot.allowDigWhilePathing(false);

// Instantiate our helper utilities and events for Capture the Flag
const rgctfUtils = new RGCTFUtils(bot);

// When a player types "start" in the chat, the bot will begin
// looking for and approaching the flag
bot.on('chat', async (username: string, message: string) => {
if (username === bot.username()) return;
if (message === 'start') {
bot.chat("Going to start capturing the flag!")
await rgctfUtils.approachFlag()
}
})

// When a player obtains the flag, this event gets called.
// In the case where that player is this bot, the bot
// navigates back to their scoring location.
bot.on(CTFEvent.FLAG_OBTAINED, async (collector: string) => {
if (collector == bot.username()) {
await rgctfUtils.scoreFlag()
}
});

// If the flag was scored, simply chat a message
bot.on(CTFEvent.FLAG_SCORED, async (teamName: string) => {
bot.chat(`Flag scored by ${teamName} team, waiting until it respawns`)
})

// Once the flag respawns on the map, look for and approach the flag.
bot.on(CTFEvent.FLAG_AVAILABLE, async (position: Vec3) => {
bot.chat("Flag is available, going to get it")
await rgctfUtils.approachFlag();
})

}

You’ll notice that our bot is not implementing some main loop that makes a decision every tick of the game — rather, our bot responds to events. In this case the bot does the following:

  • When a chat event happens (i.e. someone types in the chat), if that person said start, the bot starts to approach the flag.
  • When any player obtains the flag, if the bot is the one that collected the flag, it tries to score it.
  • When a flag is scored,

Go ahead and try this out! Type “start” in the chat, and you will begin to see your bot move toward the flag, capture the flag, and then score the flag. Once the flag respawns after 10 seconds, your bot will try again!

We will now update the bot to be more robust and implement more logic. Note that whenever you push new code using git, the bot will automatically reload. You can see the bot status, as well as the logs, inventory, and score of your bots and teams within the match dashboard.

The match dashboard is your central place to debug your bot and the match

Improving the Algorithm

Our bot is quite simple right now — it waits for us to say “start”, and then
repeatedly gets the flag. Let’s make this ready for a real multiplayer match,
by adding logic to:

  1. Automatically start our logic when the match begins (vs a chat message)
  2. Collect nearby items when waiting for the flag to respawn
  3. Add robustness for respawning

This code below is our Typescript sample and final code for our bot! Feel free to copy and read it, or visit one of our guides mentioned at the beginning of this tutorial to see the full rundown of how this works.

import { RGBot } from "rg-bot";
import RGCTFUtils, { CTFEvent } from "rg-ctf-utils";
import { Vec3 } from "vec3";

/**
* This strategy is the simplest example of how to get started
* with the rg-bot and rg-ctf-utils packages. The Bot will get
* the flag and then run back to base to score, as well as
* collect some items.
*
* rg-bot docs: https://github.com/Regression-Games/RegressionBot/blob/main/docs/api.md
* rg-ctf-utils docs: https://github.com/Regression-Games/rg-ctf-utils
*/
export function configureBot(bot: RGBot) {

// Since most blocks can't be broken on Arctic Algorithm Field,
// don't allow digging while pathfinding
bot.allowDigWhilePathing(false);

// Instantiate our helper utilities and events for Capture the Flag
const rgctfUtils = new RGCTFUtils(bot);

// track how many times we've died
let deaths = 0

bot.on('death', () => {
console.log("I have died...")
++deaths;
try {
// stop any current pathfinding goal
// @ts-ignore
bot.mineflayer().pathfinder.setGoal(null)
// @ts-ignore
bot.mineflayer().pathfinder.stop()
} catch (ex) {

}
})

bot.on('spawn', async () => {
await rgctfUtils.approachFlag();
});

// When a player obtains the flag, this event gets called.
// In the case where that player is this bot, the bot
// navigates back to their scoring location.
bot.on(CTFEvent.FLAG_OBTAINED, async (collector: string) => {
if (collector == bot.username()) {
await rgctfUtils.scoreFlag()
}
});

let isCollectingItems = false;

// If the flag was scored, collect items until the flag is available
bot.on(CTFEvent.FLAG_SCORED, async (teamName: string) => {
let previousDeaths = deaths
const codeStillRunning = () => {return previousDeaths === deaths}
bot.chat(`Flag scored by ${teamName} team, collecting items until new flag is here`)
isCollectingItems = true;
while(rgctfUtils.getFlagLocation() === null && codeStillRunning()) {
await bot.findAndCollectItemsOnGround();
await bot.waitForMilliseconds(500);
}
isCollectingItems = false;
if (codeStillRunning()) await rgctfUtils.approachFlag();
})

// Once the flag respawns on the map, look for and approach the flag, only if
// we are not busy collecting items
bot.on(CTFEvent.FLAG_AVAILABLE, async (position: Vec3) => {
if (!isCollectingItems) {
bot.chat("Flag is available, going to get it")
await rgctfUtils.approachFlag();
}
})

}

Commit and push this code using git, and your bot will automatically reload. Immediately, you should see your bot moving around to score the flag and collect items!

Next Steps

You now have a bot that can collect the flag and collect items — what’s next?

Regarding strategy, here are a few ideas:

  • How can you use the items, armor, and weapons picked up throughout the match?
  • How can you incorporate item drops into your algorithm?
  • What’s the best way to use all three of your bots?
  • How can you build a communication system between bots using the whisper functionality?
  • Should you rush for items, attack enemies, camp their base, or group up?
  • What makes for a good macro and micro strategy?
  • How can you use bows and arrows effectively?
  • Some item drops include blocks for building structures — what’s the best way to use these?

--

--