Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dotnet kit #154

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ kits/cpp/**/*/main.js
kits/cpp/**/*/main.wasm
kits/cpp/**/*.out
kits/java/**/*.class
kits/csharp/**/obj/*
kits/csharp/**/bin/*
kits/csharp/**/.vs/*
__pycache__
kits/ts/dist

Expand Down
53 changes: 53 additions & 0 deletions kits/csharp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# C# Kit

This is the folder for the C# kit. Please make sure to read the instructions as they are important regarding how you will write a bot and submit it to the competition servers.

Make sure to check our [Discord](https://discord.gg/aWJt3UAcgn) or the [Kaggle forums](https://www.kaggle.com/c/lux-ai-2021/discussion) for announcements if there are any breaking changes.

## Getting Started

To get started, download the `simple` folder from this repository.

Then navigate to that folder via command line e.g. `cd simple` or for windows `chdir simple`.

Your main code will go into `Bot/Bot.cs` and you can use create other files to help you as well. You should leave `main.py` and the `Lux` package alone in `Bot/`. Read the `Bot.Kt` file to get an idea of how a bot is programmed and a feel for the C# API.

Make sure you have dotnet core 3.1 (higher versions are probably fine too).

To confirm your setup, in your bot folder run

```
compile.bat
```

and this should produce a `Bot.dll` file in `Bot/bin/Release/netcoreapp3.1` which comprise your compiled bot. To then test run your bot, run

```
lux-ai-2021 run.bat run.bat --out=replay.json
```

which should produce no errors.

To debug your bot locally you can use any remote dotnet debugger (embedded in your preferred IDE).
First, start a game with `debug.bat` script (also increase the bot timeout):

```lux-ai-2021 run.sh debug.sh --maxtime=9999999```

Then, connect the debugger to the running process. Now you can use breakpoints and other debug features!

If you find some bugs or unfixable errors, please let an admin know via Discord, the forums, or email us.

Note that your submitted bot must include the compiled `.dll` file with it or else it will not work on the competition servers.

## Developing

Now that you have some code and you checked that your code works by trying to submit something, you are now ready to start programming your bot and having fun!

If you haven't read it already, take a look at the [design specifications for the competition](https://lux-ai.org/specs-2021). This will go through the rules and objectives of the competition.

All of our kits follow a common API through which you can use to access various functions and properties that will help you develop your strategy and bot. The markdown version is here: https://github.com/Lux-AI-Challenge/Lux-Design-2021/blob/master/kits/README.md

## Submitting to Kaggle

Not ready yet.

25 changes: 25 additions & 0 deletions kits/csharp/simple/Bot.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31727.386
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot", "Bot/Bot.csproj", "{4F2D90F4-3C60-45FF-82B0-A15E7CE6882D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4F2D90F4-3C60-45FF-82B0-A15E7CE6882D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F2D90F4-3C60-45FF-82B0-A15E7CE6882D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F2D90F4-3C60-45FF-82B0-A15E7CE6882D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F2D90F4-3C60-45FF-82B0-A15E7CE6882D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BE1F8531-39A1-4C36-8C68-A4E7E2D86C1B}
EndGlobalSection
EndGlobal
123 changes: 123 additions & 0 deletions kits/csharp/simple/Bot/Bot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Text;
using Bot.Lux;

namespace Bot
{
public class Bot
{
static void Main(string[] args)
{
var agent = new Agent();
// initialize
agent.Initialize();
while (true)
{
// Do not edit!
// wait for updates
agent.Update();

var actions = new List<string>();
var gameState = agent.GameState;
/** AI Code Goes Below! **/

var player = gameState.Players[gameState.Id];
var opponent = gameState.Players[(gameState.Id + 1) % 2];
var gameMap = gameState.Map;

var resourceTiles = new List<Cell>();
for (var y = 0; y < gameMap.Height; y++)
{
for (var x = 0; x < gameMap.Width; x++)
{
var cell = gameMap.GetCell(x, y);
if (cell.HasResource())
{
resourceTiles.Add(cell);
}
}
}

// we iterate over all our units and do something with them
foreach (var unit in player.Units)
{
if (unit.IsWorker() && unit.CanAct())
{
if (unit.GetCargoSpaceLeft() > 0)
{
// if the unit is a worker and we have space in cargo, lets find the nearest resource tile and try to mine it
Cell closestResourceTile = null;
double closestDist = 9999999;
foreach (Cell cell in resourceTiles)
{
if (cell.Resource.Type == GameConstants.RESOURCE_TYPES.COAL && !player.ResearchedCoal()) continue;
if (cell.Resource.Type == GameConstants.RESOURCE_TYPES.URANIUM && !player.ResearchedUranium()) continue;
double dist = cell.Pos.DistanceTo(unit.Pos);
if (dist < closestDist)
{
closestDist = dist;
closestResourceTile = cell;
}
}

if (closestResourceTile != null)
{
var dir = unit.Pos.DirectionTo(closestResourceTile.Pos);
// move the unit in the direction towards the closest resource tile's position.
actions.Add(unit.Move(dir));
}
}
else
{
// if unit is a worker and there is no cargo space left, and we have cities, lets return to them
if (player.Cities.Count > 0)
{
double closestDist = 999999;
CityTile closestCityTile = null;
foreach (var city in player.Cities.Values)
{
foreach (CityTile cityTile in city.CityTiles)
{
var dist = cityTile.Pos.DistanceTo(unit.Pos);
if (dist < closestDist)
{
closestCityTile = cityTile;
closestDist = dist;
}
}
}

if (closestCityTile != null)
{
var dir = unit.Pos.DirectionTo(closestCityTile.Pos);
actions.Add(unit.Move(dir));
}
}
}
}
}

// you can add debug annotations using the static methods of the Annotate class.
// actions.Add(Annotate.circle(0, 0));

/** AI Code Goes Above! **/

/** Do not edit! **/
StringBuilder commandBuilder = new StringBuilder("");
for (int i = 0; i < actions.Count; i++)
{
if (i != 0)
{
commandBuilder.Append(",");
}
commandBuilder.Append(actions[i]);
}
Console.Out.WriteLine(commandBuilder.ToString());
// end turn
agent.EndTurn();

}
}
}
}
8 changes: 8 additions & 0 deletions kits/csharp/simple/Bot/Bot.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

</Project>
128 changes: 128 additions & 0 deletions kits/csharp/simple/Bot/Lux/Agent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using System;
using System.IO;

namespace Bot.Lux
{
public class Agent
{
public GameState GameState = new GameState();
public TextReader Reader;

/**
* Constructor for a new agent User should edit this according to their `Design`
*/
public Agent()
{
Reader = Console.In;
}

/**
* Initialize Agent for the `Match` User should edit this according to their
* `Design`
*/
public void Initialize()
{
// get agent ID
GameState.Id = int.Parse(Reader.ReadLine() ?? throw new InvalidOperationException());
var mapInfo = Console.ReadLine();
if (mapInfo == null) return;
var mapInfoSplit = mapInfo.Split(" ");
var mapWidth = int.Parse(mapInfoSplit[0]);
var mapHeight = int.Parse(mapInfoSplit[1]);
GameState.Map = new GameMap(mapWidth, mapHeight);
}

/**
* Updates agent's own known state of `Match` User should edit this according to
* their `Design`.
*/
public void Update()
{
// wait for the engine to send any updates
GameState.Map = new GameMap(GameState.Map.Width, GameState.Map.Height);
GameState.Turn += 1;
GameState.Players[0].Cities.Clear();
GameState.Players[0].Units.Clear();
GameState.Players[1].Cities.Clear();
GameState.Players[1].Units.Clear();
while (true)
{
var updateInfo = Reader.ReadLine();
if (updateInfo == IOConstants.DONE)
{
break;
}
var updates = updateInfo.Split(" ");
var inputIdentifier = updates[0];
if (inputIdentifier == IOConstants.RESEARCH_POINTS)
{
var team = int.Parse(updates[1]);
GameState.Players[team].ResearchPoints = int.Parse(updates[2]);
}
else if (inputIdentifier == IOConstants.RESOURCES)
{
var type = updates[1];
var x = int.Parse(updates[2]);
var y = int.Parse(updates[3]);
var amt = (int)double.Parse(updates[4]);
GameState.Map.SetResource(type, x, y, amt);
}
else if (inputIdentifier == IOConstants.UNITS)
{
var i = 1;
var unitType = int.Parse(updates[i++]);
var team = int.Parse(updates[i++]);
var unitId = updates[i++];
var x = int.Parse(updates[i++]);
var y = int.Parse(updates[i++]);
var cooldown = double.Parse(updates[i++]);
var wood = int.Parse(updates[i++]);
var coal = int.Parse(updates[i++]);
var uranium = int.Parse(updates[i++]);
var unit = new Unit(team, unitType, unitId, x, y, cooldown, wood, coal, uranium);
GameState.Players[team].Units.Add(unit);
}
else if (inputIdentifier == IOConstants.CITY)
{
var i = 1;
var team = int.Parse(updates[i++]);
var cityId = updates[i++];
var fuel = double.Parse(updates[i++]);
var lightUpkeep = double.Parse(updates[i++]);
GameState.Players[team].Cities.Add(cityId, new City(team, cityId, fuel, lightUpkeep));
}
else if (inputIdentifier == IOConstants.CITY_TILES)
{
var i = 1;
var team = int.Parse(updates[i++]);
var cityId = updates[i++];
var x = int.Parse(updates[i++]);
var y = int.Parse(updates[i++]);
var cooldown = double.Parse(updates[i++]);
var city = GameState.Players[team].Cities[cityId];
var cityTile = city.AddCityTile(x, y, cooldown);
GameState.Map.GetCell(x, y).CityTile = cityTile;
GameState.Players[team].CityTileCount += 1;
}
else if (inputIdentifier == IOConstants.ROADS)
{
var i = 1;
var x = int.Parse(updates[i++]);
var y = int.Parse(updates[i++]);
var road = double.Parse(updates[i++]);
var cell = GameState.Map.GetCell(x, y);
cell.Road = road;
}
}
}

/**
* End a turn
*/
public void EndTurn()
{
Console.Out.Write("D_FINISH");
Console.Out.Flush();
}
}
}
30 changes: 30 additions & 0 deletions kits/csharp/simple/Bot/Lux/Annotate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace Bot.Lux
{
public class Annotate
{
public static string Circle(int x, int y)
{
return $"dc {x} {y}";
}
public static string X(int x, int y)
{
return $"dx {x} {y}";
}
public static string Line(int x1, int y1, int x2, int y2)
{
return $"dl {x1} {y1} {x2} {y2}";
}
public static string Text(int x1, int y1, string message)
{
return $"dt {x1} {y1} '{message}' 16 ";
}
public static string Text(int x1, int y1, string message, int fontSize)
{
return $"dt {x1} {y1} '{message}' {fontSize}";
}
public static string SideText(string message)
{
return $"dst '{message}'";
}
}
}
16 changes: 16 additions & 0 deletions kits/csharp/simple/Bot/Lux/Cargo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Bot.Lux
{
public class Cargo
{
public int Wood;
public int Coal;
public int Uranium;

public Cargo(int wood, int coal, int uranium)
{
Wood = wood;
Coal = coal;
Uranium = uranium;
}
}
}
Loading