├── .gitignore ├── BattleSnakeStarter.sln ├── README.md └── Starter.Api ├── Model ├── Board.cs ├── Coordinate.cs ├── Game.cs ├── Ruleset.cs ├── RulesetSettings.cs └── Snake.cs ├── Program.cs ├── Properties └── launchSettings.json ├── Requests └── GameStatusRequest.cs ├── Responses ├── InitResponse.cs └── MoveResponse.cs ├── Starter.Api.csproj ├── appsettings.Development.json └── appsettings.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.*~ 3 | project.lock.json 4 | .DS_Store 5 | *.pyc 6 | nupkg/ 7 | 8 | # Visual Studio Code 9 | .vscode 10 | 11 | # Rider 12 | .idea 13 | 14 | # User-specific files 15 | *.suo 16 | *.user 17 | *.userosscache 18 | *.sln.docstates 19 | 20 | # Build results 21 | [Dd]ebug/ 22 | [Dd]ebugPublic/ 23 | [Rr]elease/ 24 | [Rr]eleases/ 25 | x64/ 26 | x86/ 27 | build/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Oo]ut/ 32 | msbuild.log 33 | msbuild.err 34 | msbuild.wrn 35 | 36 | .vs/ -------------------------------------------------------------------------------- /BattleSnakeStarter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Starter.Api", "Starter.Api\Starter.Api.csproj", "{A81484CB-5FE0-4F6C-8724-990FF2E05622}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {A81484CB-5FE0-4F6C-8724-990FF2E05622}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {A81484CB-5FE0-4F6C-8724-990FF2E05622}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {A81484CB-5FE0-4F6C-8724-990FF2E05622}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {A81484CB-5FE0-4F6C-8724-990FF2E05622}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Battlesnake](https://play.battlesnake.com) C# Starter 2 | 3 | This is a basic implementation of the Battlesnake API. It's a great starting point for anyone wanting to program their first Battlesnake using C#. 4 | It can also be deployed to Azure, or any other cloud provider you'd like. 5 | 6 | ### Technologies Used 7 | 8 | * [Asp Net Core](https://dotnet.microsoft.com/apps/aspnet) 9 | 10 | ## Prerequisites 11 | 12 | * [Battlesnake Account](https://play.battlesnake.com) 13 | * [Azure Account](https://azure.microsoft.com/en-us/) 14 | * [GitHub Account](https://github.com) (Optional) 15 | 16 | ## Running Your Battlesnake on [Azure](https://azure.microsoft.com/en-us/) 17 | 18 | For a quick setup you'll need a [Rider](https://www.jetbrains.com/rider/) or [Visual Studio](https://visualstudio.microsoft.com/) 19 | 20 | 1. Clone this repository and open it in any mentioned IDE 21 | ``` 22 | https://github.com/neistow/battlesnake-starter-csharp.git 23 | ``` 24 | ### Rider 25 | 2. You should install [Azure Toolkit](https://plugins.jetbrains.com/plugin/11220-azure-toolkit-for-rider). 26 | 3. Right click on Starter.Api and select "Publish" -> "Publish to Azure". 27 | ![rider64_dHp9DKUBkh](https://user-images.githubusercontent.com/55974615/84885040-270ffc80-b09b-11ea-8984-05bde8edf0b5.png) 28 | ![rider64_FcBaZNPtVG](https://user-images.githubusercontent.com/55974615/84885122-427b0780-b09b-11ea-9e3f-72290e2581a4.png) 29 | 4. Choose subscription type,location of server etc. If you have login error go to "Tools" -> "Azure" and login to your account 30 | ![rider64_SB5qMCBKTM](https://user-images.githubusercontent.com/55974615/84885239-6d655b80-b09b-11ea-8488-693e393f2050.png) 31 | 5. Click Publish and wait until a link to your app appears in console and/or opens in browser. At this point you've deployed your snake. 32 | ![rider64_1xs3suV3aB](https://user-images.githubusercontent.com/55974615/84885652-ff6d6400-b09b-11ea-88c6-72ed996c5554.png) 33 | 6. If you need to update your snake simply click "publish" and select existing app, after confirmation your snake will be updated and deployed automatically. 34 | 35 | ### Visual Studio 36 | 2. Right click on Starter.Api and select "Publish" -> "App Service" -> "Create New". 37 | ![nXystE79yb](https://user-images.githubusercontent.com/55974615/84887198-144af700-b09e-11ea-80b8-b69ea9bb2eb9.png) 38 | 3. Choose subscription type,location of server etc. 39 | ![devenv_jU0squqFWl](https://user-images.githubusercontent.com/55974615/84887068-ea91d000-b09d-11ea-8da4-6224543516f9.png) 40 | 4. Click Publish and wait until a link to your app appears in console and/or opens in browser. At this point you've deployed your snake. 41 | ![devenv_jK3BxfPRi3](https://user-images.githubusercontent.com/55974615/84887103-f54c6500-b09d-11ea-8fb7-254f041e95f6.png) 42 | 5. If you need to update your snake simply click "publish" and select existing app, after confirmation your snake will be updated and deployed automatically. 43 | 44 | -------------------------------------------------------------------------------- /Starter.Api/Model/Board.cs: -------------------------------------------------------------------------------- 1 | namespace Starter.Api; 2 | 3 | /// 4 | /// The game board is represented by a standard 2D grid, oriented with (0,0) in the bottom left. 5 | /// The Y-Axis is positive in the up direction, and X-Axis is positive to the right. 6 | /// Coordinates begin at zero, such that a board that is 12x12 will have coordinates ranging from [0, 11]. 7 | /// 8 | public class Board 9 | { 10 | /// 11 | /// Height of the game board. 12 | /// Example: 11 13 | /// 14 | public int Height { get; set; } 15 | 16 | 17 | /// 18 | /// Width of the game board. 19 | /// Example: 11 20 | /// 21 | public int Width { get; set; } 22 | 23 | 24 | /// 25 | /// Array of s representing food locations on the game board. 26 | /// Example: [{"x": 5, "y": 5}, ..., {"x": 2, "y": 6}] 27 | /// 28 | public IEnumerable Food { get; set; } = new Coordinate[0]; 29 | 30 | 31 | /// 32 | /// Array of s representing all Battlesnakes remaining on the game 33 | /// board (including yourself if you haven't been eliminated). 34 | /// Example: [{"id": "snake-one", ...}, ...] 35 | /// 36 | public IEnumerable Snakes { get; set; } = new Snake[0]; 37 | 38 | 39 | /// 40 | /// Array of s representing hazardous locations on the game board. These 41 | /// will only appear in some game modes. 42 | /// Example: [{"x": 0, "y": 0}, ..., {"x": 0, "y": 1}] 43 | /// 44 | public IEnumerable Hazards { get; set; } = new Coordinate[0]; 45 | } -------------------------------------------------------------------------------- /Starter.Api/Model/Coordinate.cs: -------------------------------------------------------------------------------- 1 | namespace Starter.Api; 2 | 3 | /// 4 | /// Coordinate on the 2D grid game board. 5 | /// Coordinates begin at zero. 6 | /// 7 | public class Coordinate 8 | { 9 | public int X { get; set; } 10 | public int Y { get; set; } 11 | 12 | public Coordinate(int x, int y) 13 | { 14 | X = x; 15 | Y = y; 16 | } 17 | } -------------------------------------------------------------------------------- /Starter.Api/Model/Game.cs: -------------------------------------------------------------------------------- 1 | namespace Starter.Api; 2 | 3 | /// 4 | /// Game Object 5 | /// 6 | public class Game 7 | { 8 | /// 9 | /// A unique identifier for this Game. 10 | /// 11 | public string Id { get; set; } = string.Empty; 12 | 13 | /// 14 | /// Information about the ruleset being used to run this game. 15 | /// Example: {"name": "standard", "version": "v1.2.3"} 16 | /// 17 | public Ruleset Ruleset { get; set; } = new Ruleset(); 18 | 19 | /// 20 | /// The name of the map used to populate the game board with snakes, food, and hazards. Example: "standard" See Game Maps 21 | /// 22 | public string Map { get; set; } = string.Empty; 23 | 24 | /// 25 | /// How much time your snake has to respond to requests for this Game. 26 | /// Time is in milliseconds. 27 | /// Example: 500 28 | /// 29 | public int Timeout { get; set; } 30 | 31 | /// 32 | /// The source of this game. One of: 33 | /// tournament 34 | /// league (for League Arenas) 35 | /// arena (for all other Arenas) 36 | /// challenge 37 | /// custom (for all other games sources) 38 | /// The values for this field may change in the near future. 39 | /// 40 | public string Source { get; set; } = string.Empty; 41 | } -------------------------------------------------------------------------------- /Starter.Api/Model/Ruleset.cs: -------------------------------------------------------------------------------- 1 | namespace Starter.Api; 2 | 3 | /// 4 | /// Information about the ruleset being used to run this game. 5 | /// 6 | public class Ruleset 7 | { 8 | /// 9 | /// Name of the ruleset being used to run this game. 10 | /// Possible values include: standard, solo, royale, squad, constrictor, wrapped. 11 | /// See Game Modes for more information on each ruleset.Example: "standard" 12 | /// 13 | public string Name { get; set; } = string.Empty; 14 | 15 | /// 16 | /// The release version of the Rules module used in this game. 17 | /// Example: "version": "v1.2.3" 18 | /// 19 | public string Version { get; set; } = string.Empty; 20 | 21 | /// 22 | /// A collection of specific settings being used by the current game that control how the rules are applied. 23 | /// 24 | public RulesetSettings Settings { get; set; } = new RulesetSettings(); 25 | } 26 | -------------------------------------------------------------------------------- /Starter.Api/Model/RulesetSettings.cs: -------------------------------------------------------------------------------- 1 | namespace Starter.Api; 2 | 3 | public class RulesetSettings 4 | { 5 | /// 6 | /// Percentage chance of spawning a new food every round. 7 | /// 8 | public int FoodSpawnChance { get; set; } 9 | 10 | /// 11 | /// Minimum food to keep on the board every turn. 12 | /// 13 | public int MinimumFood { get; set; } 14 | 15 | /// 16 | /// Health damage a snake will take when ending its turn in a hazard. This stacks on top of the regular 1 damage a snake takes per turn. 17 | /// 18 | public int HazardDamagePerTurn { get; set; } 19 | 20 | public RoyaleModeRulesetSettings Royale { get; set; } = new RoyaleModeRulesetSettings(); 21 | 22 | public SquadModeRulesetSettings Squad { get; set; } = new SquadModeRulesetSettings(); 23 | 24 | public class RoyaleModeRulesetSettings 25 | { 26 | /// 27 | /// In Royale mode, the number of turns between generating new hazards (shrinking the safe board space). 28 | /// 29 | public int ShrinkEveryNTurns { get; set; } 30 | } 31 | 32 | public class SquadModeRulesetSettings 33 | { 34 | /// 35 | /// In Squad mode, allow members of the same squad to move over each other without dying. 36 | /// 37 | public bool AllowBodyCollisions { get; set; } 38 | 39 | /// 40 | /// In Squad mode, all squad members are eliminated when one is eliminated. 41 | /// 42 | public bool SharedElimination { get; set; } 43 | 44 | /// 45 | /// In Squad mode, all squad members share health. 46 | /// 47 | public bool SharedHealth { get; set; } 48 | 49 | /// 50 | /// In Squad mode, all squad members share length. 51 | /// 52 | public bool SharedLength { get; set; } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Starter.Api/Model/Snake.cs: -------------------------------------------------------------------------------- 1 | namespace Starter.Api; 2 | 3 | /// 4 | /// The snake itself. 5 | /// 6 | public class Snake 7 | { 8 | /// 9 | /// Unique identifier for this Battlesnake in the context of the current Game. 10 | /// Example: "totally-unique-snake-id" 11 | /// 12 | public string Id { get; set; } = string.Empty; 13 | 14 | /// 15 | /// Name given to this Battlesnake by its author. 16 | /// Example: "Sneky McSnek Face" 17 | /// 18 | public string Name { get; set; } = string.Empty; 19 | 20 | /// 21 | /// Health value of this Battlesnake, between 0 and 100 inclusively. 22 | /// Example: 54 23 | /// 24 | public int Health { get; set; } 25 | 26 | /// 27 | /// Array of coordinates representing this Battlesnake's location on the game board. 28 | /// This array is ordered from head to tail. 29 | /// Example: [{"x": 0, "y": 0}, ..., {"x": 2, "y": 0}] 30 | /// 31 | public IEnumerable Body { get; set; } = new Coordinate[] { new Coordinate(0, 0) }; 32 | 33 | /// 34 | /// Coordinates for this Battlesnake's head. Equivalent to the first element of the body array. 35 | /// Example: {"x": 0, "y": 0} 36 | /// 37 | public Coordinate Head { get; set; } = new Coordinate(0, 0); 38 | 39 | /// 40 | /// Length of this Battlesnake from head to tail. Equivalent to the length of the body 41 | /// array. 42 | /// Example: 3 43 | /// 44 | public int Length { get; set; } 45 | 46 | /// 47 | /// Message shouted by this Battlesnake on the previous turn. 48 | /// Example: "why are we shouting??" 49 | /// 50 | public string Shout { get; set; } = string.Empty; 51 | 52 | /// 53 | /// The previous response time of this Battlesnake, in milliseconds. 54 | /// If the Battlesnake timed out and failed to respond, the game timeout will be returned (game.timeout) 55 | /// Example: 500 56 | /// 57 | public string Latency { get; set; } = string.Empty; 58 | 59 | /// 60 | /// The squad that the Battlesnake belongs to. Used to identify squad members in Squad Mode games. 61 | /// Example: "1" 62 | /// 63 | public string Squad { get; set; } = string.Empty; 64 | 65 | /// 66 | /// The collection of customizations applied to this Battlesnake that represent how it is viewed. 67 | /// Follows the same rules as in the Info request. 68 | /// Example: {"color":"#888888", "head":"default", "tail":"default" } 69 | /// 70 | public SnakeCustomizations Customizations { get; set; } = new SnakeCustomizations(); 71 | 72 | public class SnakeCustomizations 73 | { 74 | /// 75 | /// Hex color code used to display this Battlesnake. Must start with "#" and be 7 characters long.Example: "#888888" 76 | /// 77 | public string Color { get; set; } = string.Empty; 78 | 79 | /// 80 | /// Displayed head of this Battlesnake. See Customization Guide for available optionsExample: "default" 81 | /// 82 | public string Head { get; set; } = string.Empty; 83 | 84 | /// 85 | /// Displayed tail of this Battlesnake. See Customization Guide for available optionsExample: "default" 86 | /// 87 | public string Tail { get; set; } = string.Empty; 88 | } 89 | } -------------------------------------------------------------------------------- /Starter.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using Starter.Api.Requests; 2 | using Starter.Api.Responses; 3 | 4 | var builder = WebApplication.CreateBuilder(args); 5 | var app = builder.Build(); 6 | app.UseHttpsRedirection(); 7 | 8 | /// 9 | /// This request will be made periodically to retrieve information about your Battlesnake, 10 | /// including its display options, author, etc. 11 | /// 12 | app.MapGet("/", () => 13 | { 14 | return new InitResponse 15 | { 16 | ApiVersion = "1", 17 | Author = "", 18 | Color = "#FFFFFF", 19 | Head = "default", 20 | Tail = "default" 21 | }; 22 | }); 23 | 24 | /// 25 | /// Your Battlesnake will receive this request when it has been entered into a new game. 26 | /// Every game has a unique ID that can be used to allocate resources or data you may need. 27 | /// Your response to this request will be ignored. 28 | /// 29 | app.MapPost("/start", (GameStatusRequest gameStatusRequest) => 30 | { 31 | Results.Ok(); 32 | }); 33 | 34 | /// 35 | /// This request will be sent for every turn of the game. 36 | /// Use the information provided to determine how your 37 | /// Battlesnake will move on that turn, either up, down, left, or right. 38 | /// 39 | app.MapPost("/move", (GameStatusRequest gameStatusRequest) => 40 | { 41 | var direction = new List { "down", "left", "right", "up" }; 42 | 43 | return new MoveResponse 44 | { 45 | Move = direction[Random.Shared.Next(direction.Count)], 46 | Shout = "I am moving!" 47 | }; 48 | }); 49 | 50 | /// 51 | /// Your Battlesnake will receive this request whenever a game it was playing has ended. 52 | /// Use it to learn how your Battlesnake won or lost and deallocated any server-side resources. 53 | /// Your response to this request will be ignored. 54 | /// 55 | app.MapPost("/end", (GameStatusRequest gameStatusRequest) => 56 | { 57 | Results.Ok(); 58 | }); 59 | 60 | app.Run(); -------------------------------------------------------------------------------- /Starter.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:17832", 8 | "sslPort": 44325 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "Starter.Api": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "", 24 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Starter.Api/Requests/GameStatusRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Starter.Api.Requests; 2 | 3 | public class GameStatusRequest 4 | { 5 | 6 | /// 7 | /// Object describing the game being played. 8 | /// 9 | public Game Game { get; set; } = new Game(); 10 | 11 | /// 12 | /// start: Turn number of the game being played (0 for new games). 13 | /// move: Turn number for this move. 14 | /// end: Turn number for the last turn of the game. 15 | /// 16 | public int Turn { get; set; } 17 | 18 | /// 19 | /// start: Object describing the initial state of the game board. 20 | /// move: Object describing the game board on this turn. 21 | /// end: Object describing the final state of the game board. 22 | /// 23 | public Board Board { get; set; } = new Board(); 24 | 25 | /// 26 | /// Object describing your Battlesnake. 27 | /// 28 | public Snake You { get; set; } = new Snake(); 29 | } -------------------------------------------------------------------------------- /Starter.Api/Responses/InitResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Starter.Api.Responses; 2 | 3 | public class InitResponse 4 | { 5 | /// 6 | /// Version of the Battlesnake API implemented by this Battlesnake. Currently only API version 1 is valid. Example: "1" 7 | /// 8 | public string ApiVersion { get; set; } = "1"; 9 | 10 | /// 11 | /// Username of the author of this Battlesnake. If provided, this will be used to verify ownership.Example: "BattlesnakeOfficial" 12 | /// 13 | public string? Author { get; set; } 14 | 15 | /// 16 | /// Hex color code used to display this Battlesnake. Must start with "#" and be 7 characters long.Example: "#888888" 17 | /// 18 | public string? Color { get; set; } 19 | 20 | /// 21 | /// Displayed head of this Battlesnake. See Customization Guide for available optionsExample: "default" 22 | /// 23 | public string? Head { get; set; } 24 | 25 | /// 26 | /// Displayed tail of this Battlesnake. See Customization Guide for available optionsExample: "default" 27 | /// 28 | public string? Tail { get; set; } 29 | 30 | /// 31 | /// A version number or tag for your snake. 32 | /// 33 | public string? Version { get; set; } 34 | } -------------------------------------------------------------------------------- /Starter.Api/Responses/MoveResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Starter.Api.Responses; 2 | 3 | public class MoveResponse 4 | { 5 | /// 6 | /// Your Battlesnake's move for this turn. Valid moves are up, down, left, or right.Example: "up" 7 | /// 8 | public string Move { get; set; } = "up"; 9 | 10 | /// 11 | /// An optional message sent to all other Battlesnakes on the next turn. Must be 256 characters or less.Example: "I am moving up!" 12 | /// 13 | public string? Shout { get; set; } 14 | } -------------------------------------------------------------------------------- /Starter.Api/Starter.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | enable 5 | enable 6 | 7 | 8 | -------------------------------------------------------------------------------- /Starter.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Starter.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | --------------------------------------------------------------------------------