Skip to content

Commit 37a79a7

Browse files
Add Python sample bot support: configuration, dependency installers, and build logic.
1 parent 044949c commit 37a79a7

File tree

4 files changed

+220
-0
lines changed

4 files changed

+220
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
@echo off
2+
3+
rem install-dependencies.cmd — Windows dependency installer for sample-bots/python
4+
rem Mirrors the behavior of install-dependencies.sh on macOS/Linux.
5+
rem
6+
rem Behavior:
7+
rem - Changes to the directory where this script resides
8+
rem - If .deps_installed does not exist, installs requirements from requirements.txt
9+
rem - Only creates .deps_installed if installation succeeds
10+
rem - Exits with non-zero code and message on failure
11+
12+
rem Change to the directory where this script is located
13+
cd /d "%~dp0"
14+
15+
rem Check if dependencies are already installed
16+
if not exist ".deps_installed" (
17+
echo Installing dependencies...
18+
19+
set "PY="
20+
where python3 >nul 2>nul && set "PY=python3"
21+
if not defined PY (
22+
where python >nul 2>nul && set "PY=python"
23+
)
24+
if not defined PY (
25+
echo Error: Python not found. Please install Python 3.
26+
exit /b 1
27+
)
28+
29+
%PY% -m pip install -q -r requirements.txt
30+
31+
rem Only create marker file if pip install succeeded
32+
if %errorlevel% equ 0 (
33+
rem Create marker file to indicate dependencies are installed
34+
echo. > .deps_installed
35+
echo Dependencies installed.
36+
) else (
37+
echo Error: Failed to install dependencies.
38+
exit /b %errorlevel%
39+
)
40+
)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env bash
2+
# install-dependencies.sh — macOS/Linux dependency installer for sample-bots/python
3+
# Mirrors the behavior of install-dependencies.cmd on Windows.
4+
#
5+
# Behavior:
6+
# - Changes to the directory where this script resides
7+
# - If .deps_installed does not exist, installs requirements from requirements.txt
8+
# - Only creates .deps_installed if installation succeeds
9+
# - Exits with non-zero code and message on failure
10+
11+
set -euo pipefail
12+
13+
# Change to the directory where this script is located
14+
cd -- "$(dirname -- "$0")"
15+
16+
# Helper to locate a working pip command
17+
find_pip() {
18+
if command -v python3 >/dev/null 2>&1 && python3 -m pip --version >/dev/null 2>&1; then
19+
echo "python3 -m pip"
20+
return 0
21+
fi
22+
if command -v python >/dev/null 2>&1 && python -m pip --version >/dev/null 2>&1; then
23+
echo "python -m pip"
24+
return 0
25+
fi
26+
if command -v pip3 >/dev/null 2>&1; then
27+
echo "pip3"
28+
return 0
29+
fi
30+
if command -v pip >/dev/null 2>&1; then
31+
echo "pip"
32+
return 0
33+
fi
34+
return 1
35+
}
36+
37+
if [ ! -f ".deps_installed" ]; then
38+
echo "Installing dependencies..."
39+
40+
if ! PIP_CMD=$(find_pip); then
41+
echo "Error: pip not found. Please install Python and pip." >&2
42+
exit 1
43+
fi
44+
45+
if ${PIP_CMD} install -q -r requirements.txt; then
46+
# Create marker file to indicate dependencies are installed
47+
: > .deps_installed
48+
echo "Dependencies installed."
49+
else
50+
echo "Error: Failed to install dependencies." >&2
51+
exit 1
52+
fi
53+
fi
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import java.io.PrintWriter
2+
import java.nio.file.Files.*
3+
import java.nio.file.Path
4+
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
5+
6+
description = "Robocode Tank Royale sample bots for Python"
7+
8+
version = libs.versions.tankroyale.get()
9+
10+
plugins {
11+
base // for the clean and build task
12+
}
13+
14+
val archiveDir = layout.buildDirectory.dir("archive")
15+
val archiveDirPath = archiveDir.get().asFile.toPath()
16+
17+
fun Path.botName() = fileName.toString()
18+
19+
// Shared helpers provided by parent sample-bots/build.gradle.kts
20+
@Suppress("UNCHECKED_CAST")
21+
val isBotProjectDir = rootProject.extra["isBotProjectDir"] as (Path) -> Boolean
22+
@Suppress("UNCHECKED_CAST")
23+
val copyBotFiles = rootProject.extra["copyBotFiles"] as (Path, Path) -> Unit
24+
25+
private fun writeShellScript(writer: PrintWriter, botName: String) {
26+
val shellScript = """
27+
#!/bin/sh
28+
../deps/install-dependencies.sh
29+
30+
cd -- "${'$'}(dirname -- "${'$'}0")"
31+
if command -v python3 >/dev/null 2>&1; then
32+
PY=python3
33+
elif command -v python >/dev/null 2>&1; then
34+
PY=python
35+
else
36+
echo "Error: Python not found. Please install python3 or python." >&2
37+
exit 1
38+
fi
39+
40+
exec "${'$'}PY" $botName.py
41+
""".trimIndent()
42+
43+
writer.print(shellScript)
44+
}
45+
46+
private fun writeBatchScript(writer: PrintWriter, botName: String) {
47+
// Important: We need to add the `>nul` redirection to avoid cmd processes halting
48+
val batchScript = """
49+
call ..\deps\install-dependencies.cmd
50+
51+
cd /d "%~dp0"
52+
set "PY="
53+
where python3 >nul 2>nul && set "PY=python3"
54+
if not defined PY (
55+
where python >nul 2>nul && set "PY=python"
56+
)
57+
if not defined PY (
58+
echo Error: Python not found. Please install Python 3.
59+
exit /b 1
60+
)
61+
%PY% $botName.py >nul
62+
""".trimIndent()
63+
64+
writer.print(batchScript)
65+
}
66+
67+
private fun createScriptFile(projectDir: Path, botArchivePath: Path, fileExt: String, newLine: String) {
68+
val botName = projectDir.botName()
69+
val file = botArchivePath.resolve("$botName.$fileExt").toFile()
70+
val printWriter = object : PrintWriter(file) {
71+
override fun println() {
72+
write(newLine)
73+
}
74+
}
75+
76+
printWriter.use { writer ->
77+
when (fileExt) {
78+
"sh" -> writeShellScript(writer, botName)
79+
"cmd" -> writeBatchScript(writer, botName)
80+
}
81+
}
82+
}
83+
84+
tasks {
85+
fun prepareBotFiles() {
86+
list(projectDir.toPath()).forEach { botDir ->
87+
if (isDirectory(botDir) && isBotProjectDir(botDir)) {
88+
val botArchivePath: Path = archiveDirPath.resolve(botDir.botName())
89+
90+
mkdir(botArchivePath)
91+
copyBotFiles(botDir, botArchivePath)
92+
93+
if (!botDir.toString().endsWith("Team")) {
94+
createScriptFile(botDir, botArchivePath, "cmd", "\r\n")
95+
createScriptFile(botDir, botArchivePath, "sh", "\n")
96+
}
97+
}
98+
}
99+
}
100+
101+
fun prepareDepsDir() {
102+
// Create a deps folder and copy dependency installers + requirements.txt
103+
val depsDir = archiveDirPath.resolve("deps")
104+
mkdir(depsDir)
105+
106+
// Copy install-dependencies scripts from assets
107+
val assetsDir = project.projectDir.toPath().resolve("assets")
108+
copy(assetsDir.resolve("install-dependencies.cmd"), depsDir.resolve("install-dependencies.cmd"), REPLACE_EXISTING)
109+
copy(assetsDir.resolve("install-dependencies.sh"), depsDir.resolve("install-dependencies.sh"), REPLACE_EXISTING)
110+
111+
// Copy requirements.txt from bot-api/python into deps
112+
val requirements = rootProject.projectDir.toPath().resolve("bot-api/python/requirements.txt")
113+
if (exists(requirements)) {
114+
copy(requirements, depsDir.resolve("requirements.txt"), REPLACE_EXISTING)
115+
} else {
116+
throw GradleException("requirements.txt not found at: ${requirements.toAbsolutePath()}")
117+
}
118+
}
119+
120+
named("build") {
121+
doLast {
122+
prepareBotFiles()
123+
prepareDepsDir()
124+
}
125+
}
126+
}

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ include("bot-api:python")
2727
// Sample Bots archives
2828
include("sample-bots:java")
2929
include("sample-bots:csharp")
30+
include("sample-bots:python")
3031

3132
// Docs
3233
include("buildDocs")

0 commit comments

Comments
 (0)