Halite is designed for all levels of coding enthusiasts—from high school students to senior engineers. The simplest Halite bot requires only 10 lines of code, but bots can get ever more advanced. Players may find themselves surprised: we’ve learned from thousands of hours of gameplay that it’s not always the most complicated algorithm that wins. Creativity and insight are highly rewarded! So code well — a bot’s fate depends on it.
-Halite was conceived of by Benjamin Spector, who partnered with his high school class-mate Michael Truell to develop the game. After receiving positive feedback on the Halite, the pair continually revised the game, extended it into the cloud and developed additional execution, leaderboard, and web interface capabilities.
+Halite was conceived of and developed by Benjamin Spector and Michael Truell. Ben largely wrote the game implementation and starter packages, while Michael was primarily responsible for the website and the competition backend infrastructure. After receiving positive feedback on the Halite, the pair continually revised the game, extended it into the cloud and developed additional execution, leaderboard, and web interface capabilities.
Two Sigma, having had a history of playful programming challenges for its mathematical and software-oriented teams (e.g., see the Robotic Air Hockey Competition) retained Ben and Michael as 2016 summer interns to further develop Halite and then run an internal Halite Challenge. The team incorporated feedback from many, and about thirty-five players competed in a successful 3-week tournament in August.
@@ -28,7 +28,7 @@To help productize and orchestrate the public launch, Two Sigma reached out to Cornell Tech, a leader in graduate tech education. With a shared interest in encouraging programming, entrepreneurship, and growth of the thriving New York tech scene, the two partners initiated the public Halite competition in November 2016. Cornell Tech is providing ongoing game support and community management, and by working closely with the online gaming community, it will empower players to collaborate, learn and have fun.
-Many have contributed to Halite beyond Ben’s and Michael’s invention and engineering; they include Eric Abrego, Matt Adereth, Trammel Hudson, Emily Malloy, Arnaud Sahuguet, and Scott Spinner. And, no doubt, much credit should also be provided to users who are sending questions and comments to the forums.
+Many have contributed to Halite beyond Ben’s and Michael’s invention and engineering; they include Jaques Clapauch, Eric Abrego, Matt Adereth, Trammel Hudson, Emily Malloy, Arnaud Sahuguet, and Scott Spinner. And, no doubt, much credit should also be provided to users who are sending questions and comments to the forums.
May the best bot win!
diff --git a/website/advanced_command_line.php b/website/advanced_command_line.php index 80de8452..10a7231a 100644 --- a/website/advanced_command_line.php +++ b/website/advanced_command_line.php @@ -2,7 +2,7 @@ -The Halite environment is responsible for running games between bots and outputting appropriate data and files upon the end of a game. The downloadable version is the same version used on the servers.
@@ -25,9 +25,12 @@-t
: disables timeouts for the duration of the game.-q
: turns on quiet output. Output will take the form of:
-o
option is also specified, lines with the command used to run each bot (one bot per line).n
players in the game, n
lines like so: playerID rank
n
players in the game, n
lines like so: playerID rank lastFrameAlive
-s
: provides the seed to the map generator. If this is not provided, it will use a time-based seed.In this guide, we will detail a couple of useful practices to follow when building your Halite bot.
+In this guide, we will list a couple of simple, useful practices to follow when building your Halite bot.
Stdout and stdin in are used to communicate with the game environment. As such, you cannot use functions like System.out.println, print(), or std::cout. Instead, print debugging information to a log file.
+Stdout and stdin in are used to communicate with the game environment. As such, you cannot use functions like System.out.println
, print()
, or std::cout
. Instead, print debugging information to a log file.
Before submitting a new bot to the online leaderboard, we recommend running some games against the version of your bot that is currently on the leaderboard. If your new bot consistently wins, then put it up!
When debugging latency issues with your bot, it can be helpful to disable game environment timeouts. To do so, append the -t flag to your environment command (e.g. ./environment -d "30 30" "python3 MyBot.py" "python3 RandomBot.py" -t).
-When your bot times out or errors on our game servers, we save and display a log file with debugging information including the time your bot took each turn, its output each turn, and its final output from stdout and stderr.
-To find these log files, visit your homepage: https://halite.io/user.php. Just click the download log button to grab your error log for a game:
+When debugging latency issues with your bot, it can be helpful to disable game environment timeouts. To do so, append the -t
flag to your environment command (e.g. ./environment -d "30 30" "python3 MyBot.py" "python3 RandomBot.py" -t
).
There is a community contributed method for running a Halite bot from a custom debugger locally. More on this can be found here on the forums.
All compilation and game execution is done on AWS EC2 m3.medium servers running Ubuntu 16.04. They have the following specs: @@ -31,7 +31,7 @@
Bot compilation is done using this autocompile script.
-To facilitate the installation of custom software, we allow users to include an install script. If a file named install.sh
exists in your submission, it is run as a bash script under the root user in a sandbox with internet access and 10 minutes of runtime. Bots may only read and write to their current directory, so all files that you want to be available at runtime must be installed locally. For more on using 3rd party libraries, click here.
To facilitate the installation of custom software, we allow users to include an install script. If a file named install.sh
exists in your submission, it is run as a bash script under the root user in a sandbox with internet access and 10 minutes of runtime. Bots may only read and write to their current directory, so all files that you want to be available at runtime must be installed locally. For more on using 3rd party libraries, click here.
Your main file must be called MyBot
. Your language is recognized using the file extension of your MyBot
file. The appropriate file extensions for each language are:
You submit a zip file containing your MyBot
file and any other files needed to compile and run your MyBot
file.
Instead of packaging up your dependencies inside your zip file, you may include a bash file named install.sh
that will be run before your bot is compiled.
It will be run with internet access and write access to only its current directory. It may run for a maximum of 10 minutes and will not be able to make global installation changes (i.e. apt-get
will not work).
The following package managers are already installed on the server and can be used to install dependencies locally:
+ +pip3
bundler
npm
curl
is also available and can be used to download additional runtimes, tools, and environments.
If your library isn't on a package manager that supports local installation and you can’t download it with curl
, you are going to have to compile it on our game servers. Include the source of you library in your bot's zip file and put compilation instructions in the install.sh
file.
For convenience's sake, we include tensorflow
, keras
(using a tensorflow
backend), numpy
, scipy
, scikit-learn
, pillow
, and h5py
on our game servers. Just import these libraries from your python files like normal!
Bot compilation is done using this autocompile script. Many languages will be properly autodetected and compiled if needed without the need for an install.sh
script.
Your main file must be called MyBot
. Your language is recognized using the file extension of your MyBot
file. The appropriate file extensions for each language are:
.java
.py
.cpp
and .h(pp)
.cs
.toml
(for your Cargo.toml
) and .rs
(for your Rust source).scala
.rb
.go
.php
.js
.ml
.clj
.c
See the Game Server Reference for details about compiler and runtime versions.
+ +If you are using a language that is generic or that does not have first class support on the server, you can include a file named LANGUAGE
containing the name of the language you are using. This will be used only for display on the rankings and in your profile.
For JVM languages, you can submit a jar file inside of your zip file instead of source files. The jar will be executed java -jar MyBot.jar
so you need to define a Main-Class header in the manifest.
You may supply a run.sh
script to control how your bot is run. Many languages will be properly autodetected and run without the need for an install.sh
script. You should only include a custom run.sh
script if you have a real need for one.
You could use a run.sh
file to use a custom runtime such as PyPy instead of the default Python 3.
When your bot times out or errors on our game servers, we save and display a log file with debugging information including the time your bot took each turn, its output each turn, and its final output from stdout and stderr.
+ +To find these log files, visit your homepage. Just click the download log button to grab your error log for a game.
+ +Below is a list of useful and/or fun resources that were created by the Halite community. Especially popular resources will be 'ed.
+ +Your bot timed out in a game for the first time. This happens when your bot doesn't respond in 15 seconds of a game's start or 1 second of a turn's start. A timeout may be the result of a runtime error in your bot. When your bot times out, its pieces become part of the map and it is ejected from the game.
Here is a visualization of the game in which your bot timed out.
Here is your bot's error log. An error log contains your bot's output (from stdout and stderr) and the time it took per turn. For more on error logs, see the dev guide.
"; - $this->sendNotification($storedUser, "First Bot Timeout/Error", $message, -1); + $message = "Your bot timed out in a game for the first time. This happens when your bot doesn't respond in 15 seconds of a game's start or 1 second of a turn's start. A timeout may be the result of a runtime error in your bot. When your bot times out, its pieces become part of the map and it is ejected from the game.
Here is a visualization of the game in which your bot timed out.
Here is your bot's error log. An error log contains your bot's output (from stdout and stderr) and the time it took per turn.
"; + $this->sendNotification($user, "First Bot Timeout/Error", $message, -1); } } // Update mu and sigma for the players usort($users, function($a, $b) { - return $a->rank > $b->rank; + return $a['rank'] > $b['rank']; }); $rankings = array(); foreach($users as $user) { - array_push($rankings, $user->mu); - array_push($rankings, $user->sigma); + array_push($rankings, $user['mu']); + array_push($rankings, $user['sigma']); } exec("python3 updateTrueskill.py ".implode(' ', $rankings), $lines); var_dump($lines); for($a = 0; $a < count($users); $a++) { $components = explode(' ', $lines[$a]); - $this->insert("UPDATE User SET mu=".$this->mysqli->real_escape_string($components[0]).", sigma=".$this->mysqli->real_escape_string($components[1])." WHERE userID=".$this->mysqli->real_escape_string($users[$a]->userID)); + $this->insert("UPDATE User SET mu=".$this->mysqli->real_escape_string($components[0]).", sigma=".$this->mysqli->real_escape_string($components[1])." WHERE userID=".$this->mysqli->real_escape_string($users[$a]['userID'])." AND numSubmissions=".$this->mysqli->real_escape_string($users[$a]['numSubmissions'])); } // Update overall rank of everyone @@ -254,10 +270,13 @@ protected function game() { usort($allUsers, function($a, $b) { return $a['mu']-3*$a['sigma'] < $b['mu']-3*$b['sigma']; }); + $query = "UPDATE User set rank = CASE"; for($userIndex = 0; $userIndex < count($allUsers); $userIndex++) { $rank = $userIndex+1; - $this->insert("UPDATE User SET rank={$rank} WHERE userID={$allUsers[$userIndex]['userID']}"); + $query .= " WHEN userID = {$allUsers[$userIndex]['userID']} THEN {$rank}"; } + $query .= " ELSE rank END;"; + $this->insert($query); } } diff --git a/website/api/web/WebsiteAPI.php b/website/api/web/WebsiteAPI.php index 250cfc62..e51cf919 100644 --- a/website/api/web/WebsiteAPI.php +++ b/website/api/web/WebsiteAPI.php @@ -18,7 +18,7 @@ include dirname(__FILE__).'/../API.class.php'; define("ORGANIZATION_WHITELIST_PATH", dirname(__FILE__)."/../../organizationWhitelist.txt"); -define("USER_TO_SERVER_RATIO", 30); +define("USER_TO_SERVER_RATIO", 100); define("WORKER_LIMIT", 50); class WebsiteAPI extends API{ @@ -69,6 +69,7 @@ private function isLoggedIn() { private function getUsers($query, $privateInfo=false) { $users = $this->selectMultiple($query); + $numUsers = $this->numRows("SELECT COUNT(*) FROM User WHERE isRunning=1"); foreach($users as &$user) { if($privateInfo == false) { unset($user['email']); @@ -77,7 +78,7 @@ private function getUsers($query, $privateInfo=false) { } if(intval($user['isRunning']) == 1) { - $percentile = intval($user['rank']) / $this->numRows("SELECT * FROM User WHERE isRunning=1"); + $percentile = intval($user['rank']) / $numUsers; if($percentile < 1/64) $user['tier'] = "Diamond"; else if($percentile < 1/16) $user['tier'] = "Gold"; else if($percentile < 1/4) $user['tier'] = "Silver"; @@ -94,6 +95,20 @@ private function getLoggedInUser() { if(isset($_SESSION['userID'])) return $this->getUsers("SELECT * FROM User WHERE userID={$_SESSION['userID']}", true)[0]; } + /** + * Helper to interface with the database and get high schools based on the filters. + */ + private function getHS($name=null, $state=null) { + $query_string = "SELECT * FROM HighSchool "; + if(!empty($name) && isset($name)) { + $query_string = $query_string."WHERE name='".$this->mysqli->real_escape_string($name)."' "; + } + if(!empty($state) && isset($state)) { + $query_string = $query_string.(!empty($name) && isset($name)?"AND":"WHERE")." state='".$this->mysqli->real_escape_string($state)."' "; + } + return $this->selectMultiple($query_string."ORDER BY name ASC"); + } + private function getOrganizationForEmail($email) { $emailDomain = explode('@', $email)[1]; $rows = explode("\n", rtrim(file_get_contents(ORGANIZATION_WHITELIST_PATH))); @@ -163,11 +178,11 @@ protected function user() { $githubUser = json_decode($gitHub->request('user'), true); $email = json_decode($gitHub->request('user/emails'), true)[0]; - if($this->numRows("SELECT userID FROM User WHERE oauthProvider=1 and oauthID={$githubUser['id']}") > 0) { // Already signed up + if($this->numRows("SELECT COUNT(*) FROM User WHERE oauthProvider=1 and oauthID={$githubUser['id']}") > 0) { // Already signed up $_SESSION['userID'] = $this->select("SELECT userID FROM User WHERE oauthProvider=1 and oauthID={$githubUser['id']}")['userID']; } else { // New User - $numActiveUsers = $this->numRows("SELECT userID FROM User WHERE isRunning=1"); + $numActiveUsers = $this->numRows("SELECT COUNT(*) FROM User WHERE isRunning=1"); $this->insert("INSERT INTO User (username, githubEmail, oauthID, oauthProvider, rank) VALUES ('{$githubUser['login']}', '{$email}', {$githubUser['id']}, 1, {$numActiveUsers})"); $_SESSION['userID'] = $this->mysqli->insert_id; } @@ -190,9 +205,27 @@ protected function email() { $this->insert("UPDATE User SET email=githubEmail, organization='$organization', isEmailGood=1 WHERE userID = {$user['userID']}"); } else if($user != null && isset($_GET['newEmail'])) { $verificationCode = rand(0, 9999999999); - $this->insert("UPDATE User SET email='".$this->mysqli->real_escape_string($_GET['newEmail'])."', verificationCode = '{$verificationCode}' WHERE userID = {$user['userID']}"); - $user["email"] = $_GET["newEmail"]; + if(isset($_GET['newLevel']) && $_GET['newLevel'] == 'High School') { + if(empty($this->getHS($_GET['newInstitution'], null))) { + # The only way this error should occur is if users manually try to game it (i.e.: REST calls) + # As such we can just print their input is incorrect rather than getting a better landing page. + echo "INVALID INPUT: EITHER INSTITUTION OR SCRIMMAGE ARE NOT FROM AVAILABLE OPTIONS."; + die(); + } + $this->insert("UPDATE User SET email='".$this->mysqli->real_escape_string($_GET['newEmail']). + "', level='".$this->mysqli->real_escape_string($_GET['newLevel']). + "', organization='".$this->mysqli->real_escape_string($_GET['newInstitution']). + "', verificationCode = '{$verificationCode}' WHERE userID = {$user['userID']}"); + } else if(isset($_GET['newLevel'])) { + $this->insert("UPDATE User SET email='".$this->mysqli->real_escape_string($_GET['newEmail']). + "', level='".$this->mysqli->real_escape_string($_GET['newLevel']). + "', organization='".$this->getOrganizationForEmail($this->mysqli->real_escape_string($_GET['newEmail'])). + "', verificationCode = '{$verificationCode}' WHERE userID = {$user['userID']}"); + } else { + $this->insert("UPDATE User SET email='".$this->mysqli->real_escape_string($_GET['newEmail'])."', verificationCode = '{$verificationCode}' WHERE userID = {$user['userID']}"); + } + $user["email"] = $_GET["newEmail"]; $this->sendNotification($user, "Email Verification", "Click here to verify your email address.
", 0, false, true); } else if(isset($_GET['verificationCode'])) { if($user == null) { @@ -249,6 +282,14 @@ protected function history() { } } + /* High School Endpoint + * + * Simple retrieval from the high school store. All participating high schools should be here. + */ + protected function highSchool() { + return $this->getHS(isset($_GET["name"])?$_GET["name"]:null, isset($_GET["state"])?$_GET["state"]:null); + } + /* User Notification Endpoint * * Allows the downloading of all of the notifications a user has recieved over email. @@ -274,16 +315,20 @@ protected function game() { $versionNumber = isset($_GET['versionNumber']) ? intval($_GET['versionNumber']) : $this->select("SELECT numSubmissions FROM User WHERE userID=$userID")['numSubmissions']; $gameArrays = $this->selectMultiple("SELECT g.* FROM GameUser gu INNER JOIN Game g ON g.gameID = gu.gameID WHERE gu.userID = $userID and gu.versionNumber = $versionNumber and gu.gameID < $startingID ORDER BY gu.gameID DESC LIMIT $limit"); + } else { + $previousID = isset($_GET['previousID']) ? intval($_GET['previousID']) : 0; + $limit = isset($_GET['limit']) ? intval($_GET['limit']) : 20; + $gameArrays = $this->selectMultiple("SELECT * FROM Game WHERE gameID > $previousID ORDER BY gameID DESC LIMIT $limit"); + } - // Get each game's info - foreach ($gameArrays as &$gameArray) { - $gameID = $gameArray['gameID']; + // Get each game's info + foreach ($gameArrays as &$gameArray) { + $gameID = $gameArray['gameID']; - // Get information about users - $gameArray['users'] = $this->selectMultiple("SELECT gu.userID, gu.errorLogName, gu.rank, u.username, u.oauthID FROM GameUser gu INNER JOIN User u ON u.userID=gu.userID WHERE gu.gameID = $gameID"); - } - return $gameArrays; - } + // Get information about users + $gameArray['users'] = $this->selectMultiple("SELECT gu.userID, gu.versionNumber, gu.errorLogName, gu.rank, u.username, u.oauthID, u.mu, u.sigma, u.rank AS userRank FROM GameUser gu INNER JOIN User u ON u.userID=gu.userID WHERE gu.gameID = $gameID"); + } + return $gameArrays; } /* Bot File Endpoint @@ -294,6 +339,10 @@ protected function botFile() { // Mark a new botfile for compilation if valid. Return error otherwise if($this->isLoggedIn() && isset($_FILES['botFile']['name'])) { $user = $this->getLoggedInUser(); + + if(isset($this->config["compState"]["closeSubmissions"]) && $this->config["compState"]["closeSubmissions"]) { + return "Sorry, bot submissions are closed."; + } if($user['compileStatus'] != 0) { return "Compiling"; @@ -315,8 +364,8 @@ protected function botFile() { if(intval($this->config['test']['isTest']) == 0) $this->sendNotification($user, "Bot Received", "We have received and processed the zip file of your bot's source code. In a few minutes, our servers will compile your bot, and you will receive another email notification, even if your bot has compilation errors.
", 0); // AWS auto scaling - $numActiveUsers = $this->numRows("SELECT userID FROM User WHERE isRunning=1"); - $numWorkers = $this->numRows("SELECT workerID FROM Worker"); + $numActiveUsers = $this->numRows("SELECT COUNT(*) FROM User WHERE isRunning=1"); + $numWorkers = $this->numRows("SELECT COUNT(*) FROM Worker"); if($numWorkers > 0 && $numWorkers < WORKER_LIMIT && $numActiveUsers / $numWorkers > USER_TO_SERVER_RATIO) { echo shell_exec("python3 openNewWorker.py > /dev/null 2>/dev/null &"); } @@ -403,6 +452,23 @@ protected function stats() { else if(isset($_GET['numActive'])) { return mysqli_query($this->mysqli, "SELECT userID FROM User WHERE isRunning=1")->num_rows; } + + // Get the median mu and sigma of active users + else if(isset($_GET['scoreMedians'])) { + $medians = array(); + $medians["mu"] = $this->select("SELECT AVG(tbl.mu) as medianMu FROM ( + SELECT @rownum:=@rownum+1 as row, mu FROM User, (SELECT @rownum:=0) rn + WHERE isRunning=1 ORDER BY mu + ) as tbl + WHERE tbl.row in (floor((@rownum+1)/2), floor((@rownum+2)/2))")["medianMu"]; + + $medians["sigma"] = $this->select("SELECT AVG(tbl.sigma) as medianSigma FROM ( + SELECT @rownum:=@rownum+1 as row, sigma FROM User, (SELECT @rownum:=0) rn + WHERE isRunning=1 ORDER BY sigma + ) as tbl + WHERE tbl.row in (floor((@rownum+1)/2), floor((@rownum+2)/2))")["medianSigma"]; + return $medians; + } } /* Announcement Endpoint diff --git a/website/archiveStarterPackages.sh b/website/archiveStarterPackages.sh index 981d8c7a..3fc5ce72 100755 --- a/website/archiveStarterPackages.sh +++ b/website/archiveStarterPackages.sh @@ -15,7 +15,9 @@ mkdir Halite-Python-Starter-Package \ Halite-PHP-Starter-Package \ Halite-JavaScript-Starter-Package \ Halite-OCaml-Starter-Package \ - Halite-Clojure-Starter-Package + Halite-Clojure-Starter-Package \ + Halite-C-Starter-Package \ + Halite-Julia-Starter-Package cp -r Python/* Halite-Python-Starter-Package/ cp -r Java/* Halite-Java-Starter-Package/ @@ -29,6 +31,8 @@ cp -r PHP/* Halite-PHP-Starter-Package/ cp -r JavaScript/* Halite-JavaScript-Starter-Package/ cp -r OCaml/* Halite-OCaml-Starter-Package/ cp -r Clojure/* Halite-Clojure-Starter-Package/ +cp -r C/* Halite-C-Starter-Package/ +cp -r Julia/* Halite-Julia-Starter-Package/ cp -r Scala/* Halite-Scala-Starter-Package/ rm Halite-Scala-Starter-Package/MyBot.java @@ -45,6 +49,8 @@ zip -r Halite-PHP-Starter-Package.zip Halite-PHP-Starter-Package/ zip -r Halite-JavaScript-Starter-Package.zip Halite-JavaScript-Starter-Package/ zip -r Halite-OCaml-Starter-Package.zip Halite-OCaml-Starter-Package/ zip -r Halite-Clojure-Starter-Package.zip Halite-Clojure-Starter-Package/ +zip -r Halite-C-Starter-Package.zip Halite-C-Starter-Package/ +zip -r Halite-Julia-Starter-Package.zip Halite-Julia-Starter-Package/ mkdir -p ../website/downloads/starterpackages mv *.zip ../website/downloads/starterpackages diff --git a/website/associate.php b/website/associate.php new file mode 100644 index 00000000..cfa4f050 --- /dev/null +++ b/website/associate.php @@ -0,0 +1,73 @@ + + + + + + +In this tutorial, we'll go through the code that powers the random bot and add a couple heuristics to it. This will hopefully help you fully understand Halite and set you on your way to leaderboard domination.
-The code in this tutorial can be found at the following links for Python, Java, and C++.
+The code in this tutorial can be found at the following links for Python, Java, and C++.
Make sure that you have read Introducing Halite and followed the setup procedures described there.
Now open up the MyBot file in your favorite editor and let's get started!
@@ -27,28 +27,30 @@Now that you know how the game works, how do the two random starter bots work? How does one code a Halite bot? Here is the source from the main file of our python starter bot:
- +Let's walk through it line by line.
-First we import a couple of helper files that are included in the starter packages:
+First we make some imports from the hlt.py helper file that is included in the starter package:
- + -Then we get our ID (each player has a unique identifier that is associated with their pieces) and the game initial map from the environment.
-We send back the name of our bot. This is used in game replays.
+Then we get our ID (each player has a unique identifier that is associated with their pieces) and the initial game map from the environment. We send back the name of our bot. This is used in game replays.
- + -Now we start our game loop. Each frame let's initialize a list of moves and get the current map:
- +Now we start our game loop:
+ -Let's cycle through all of the pieces on the map. If a piece is owned by us, let's order it to move in a random direction.
+Each turn, update the current map from the game environment:
+ - +Let's create our list of moves by cycling through all the pieces on the map. If a piece is owned by us, let's instruct it to move in a random direction.
+ +Finally, let's send all of our moves to the environment:
- +And that's random bot!
@@ -59,26 +61,27 @@Let's wrap the movement logic inside a function of its own. This function will take the location of a piece and will return the piece's movement.
+Let's wrap the movement logic inside a function of its own. This function will take a piece as input and will return the piece's movement.
Now we can improve our bot by making sure that we tell all of our zero strength pieces to remain still.
- +Our bot still moves its pieces around a lot (only a bit over one out of five turns will a piece stay still). This costs us a lot of strength (since a piece doesn't gain any strength on turns that it moves). To increase our utilization of our production, let's have pieces only move once their strength equals their production times some factor X. We're using 5 as the value of X in this example, but this is arbitrary.
- +When building a Halite bot, one of our goals should be moving strength out of your territory quickly and with little production loss. Our current bot is terrible at this. Its pieces move randomly around our territory, going nowhere, costing us production, and often losing strength to the strength cap.
To improve this, let's just mandate that our pieces move only north and west. Since the map is wrap-around, we can still capture all of the board with this strategy!
- +Once our pieces get to our borders, we don't want them to randomly attack just any square (or worse, move back into our territory), as we do now. One problem with this random strategy is that we may attack a map square that has more strength than us. This is unproductive (pun implied) since moving onto the map square costs us a turn of production and we don't actually gain anything. We just diminish the squares strength.
To improve on our current combat, if there is an enemy or map square that is adjacent to one of our pieces with less strength than our piece, let's take it.
- + -That's really up to you! How you improve your bot from here is where you step into the competition.
-That said, if you're looking for more ideas or a stronger starting base, nmlaguti wrote a tutorial here that we highly recommend.
+That said, if you're looking for more ideas or a stronger starting base, nmalaguti wrote a tutorial that walks you through improving your combat, piece management, and expansion.
+If you're interested in machine learning, Two Sigma's own Brian van Leeuwen authored an introductory deep learning tutorial.
Good luck!
To play games of Halite locally, you will need the game environment. As of this writing we support Windows, Linux and OSX platforms. You can download the game environment here. Place the downloaded binary (halite or halite.exe) in your starter kit folder.
-To simulate a game, simply runGame.sh (Linux and macOS) or runGame.bat (Windows). This command will run a game between my MyBot and RandomBot (both are just copies of each other at this point) on a grid of size 30x30.
+To simulate a game, simply issue the command ./runGame.sh (Linux and macOS) or runGame.bat (Windows). This command will run a game between my MyBot and RandomBot (both are just copies of each other at this point) on a grid of size 30x30.
The output should look like this and the details of the game will be stored in a file with the "hlt" extension (35538-124984302.hlt in the example below).
-$ . runGame.sh
+ $ ./runGame.sh
python3 MyBot.py
python3 RandomBot.py
Init Message sent to player 2.
@@ -55,8 +55,10 @@
Visualizing a game
- The console output from the game environment gives just the outcome of the game. To replay the game, drag and drop the file to the visualizer to get a visualization like this one:
-
+ The console output from the game environment gives just the outcome of the game. To replay the game, drag and drop the file to the visualizer. Since the starter pack is very bad at playing Halite, your visualization will be quite dull.
+ Here's a taste of what some very good Halite bots look like:
+
+
Halite game rules
What do all of these pretty squares mean?
@@ -65,6 +67,7 @@
When two or more pieces from the same player try to occupy the same site, the resultant piece gets the sum of their strengths (this strength is capped at 255).
When pieces with different owners move onto the same site or cardinally adjacent sites, the pieces are forced to fight, and each piece loses strength equal to the strength of its opponent. When a player's piece moves onto an unowned site, that piece and the unowned piece fight, and each piece loses strength equal to the strength of its opponent.
When a piece loses all of its strength, it dies and is removed from the grid.
+ For the full rules, see here.
How do we program a bot?
Move on to Improving the Random Bot.
@@ -75,8 +78,14 @@
+
+
+
+
+
+
diff --git a/website/basics_quickstart.php b/website/basics_quickstart.php
index 68520512..5937d325 100644
--- a/website/basics_quickstart.php
+++ b/website/basics_quickstart.php
@@ -38,8 +38,9 @@
Congratulations. You are now an official contestant!
It may be up to 10 minutes before your bot has played a few games. In the meantime, move onto Introducing Halite.
- Need Help? Have Feedback? Want to Talk?
- Please post on the forums. For more unstructured conversations, join our discord.
+ Join the Community
+ If you need help or have feedback, please visit the forums! If you’d like to hang out and chat with other players, come join the official discord.
+
- This set of starter packages was uploaded on November 13th. We uploaded a Go starter package. + On December 31st, we patched the version of the Java starter package that we had released on December 30th.
The environment is on version 1.0. This version of the environment was posted on November 2nd.
+The environment is on version 1.1. This version of the environment was posted on December 9th.
Execute:
@@ -47,7 +49,7 @@You should see a file titled "halite" in your current directory. This is the game environment. Put it in the root directory of your starter package.
Download halite.exe. Put it in the root directory of your starter package.
+Download the halite.exe executable from here. Put it in the root directory of your starter package.
Extract this archive.
diff --git a/website/email.php b/website/email.php index 3768fb39..f1aaa94f 100644 --- a/website/email.php +++ b/website/email.php @@ -44,7 +44,6 @@If you add a bash file named install.sh to the same directory as your bot source, it will be run with internet access and write access to its current directory before any bot compilation. It may run for a maximum of 10 minutes.
- -You must install all libraries locally, even if through a package manager. Because of this, package managers that only support global installation (such as apt-get) may not be used.
-The following package managers are installed ahead of time on the Halite game servers:
-- If you would like us to add another package manager to this list, post on the forums. -
- -Here is an example install.sh file for a bot that uses the numpy library:
- -It's just one line!
- -If your library isn't on a package manager that supports local installation, you are going to have to compile it on our game servers. Include the source of you library in your bot's zip file and put compilation instructions in the install.sh file.
-