Add project files.
This commit is contained in:
parent
1695d2a18b
commit
9bd9a063f8
9
Codingame.csproj
Normal file
9
Codingame.csproj
Normal file
@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
25
Codingame.sln
Normal file
25
Codingame.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33122.133
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Codingame", "Codingame.csproj", "{4C43862B-37C5-4543-BD26-08875DC59CAC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4C43862B-37C5-4543-BD26-08875DC59CAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4C43862B-37C5-4543-BD26-08875DC59CAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4C43862B-37C5-4543-BD26-08875DC59CAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4C43862B-37C5-4543-BD26-08875DC59CAC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {4EE8EC05-1729-4E48-AC79-5847801FFCA1}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
174
FallChallenge2022.cs
Normal file
174
FallChallenge2022.cs
Normal file
@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Codingame {
|
||||
public class FallChallenge2022 {
|
||||
public static string ReadInput() => Console.ReadLine() ?? throw new InvalidProgramException("No input available!");
|
||||
|
||||
public static void Main(string[] args) {
|
||||
string[] inputs;
|
||||
inputs = ReadInput().Split(' ');
|
||||
var width = int.Parse(inputs[0]);
|
||||
var height = int.Parse(inputs[1]);
|
||||
var state = new GameState(width, height, new FieldState[width, height]);
|
||||
|
||||
// game loop
|
||||
while (true) {
|
||||
inputs = ReadInput().Split(' ');
|
||||
state.MyMatter = int.Parse(inputs[0]);
|
||||
state.OppMatter = int.Parse(inputs[1]);
|
||||
for (var i = 0; i < height; i++) for (var j = 0; j < width; j++) {
|
||||
ref var field = ref state.Fields[j, i];
|
||||
inputs = ReadInput().Split(' ');
|
||||
field.ScrapAmount = int.Parse(inputs[0]);
|
||||
field.Owner = (Owner)int.Parse(inputs[1]);
|
||||
if (!Enum.IsDefined(field.Owner)) throw new InvalidProgramException("Invalid owner!");
|
||||
field.Units = int.Parse(inputs[2]);
|
||||
field.Recycler = int.Parse(inputs[3]) == 1;
|
||||
field.CanBuild = int.Parse(inputs[4]) == 1;
|
||||
field.CanSpawn = int.Parse(inputs[5]) == 1;
|
||||
field.InRangeOfRecycler = int.Parse(inputs[6]) == 1;
|
||||
}
|
||||
|
||||
// Write an action using Console.WriteLine()
|
||||
// To debug: Console.Error.WriteLine("Debug messages...");
|
||||
|
||||
var commands = GetCommands(state).ToList() is { Count: > 0 } cmds ? cmds : Command.Empty;
|
||||
Console.WriteLine(string.Join(';', commands.Select(i => i.GetCommandString())));
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Command> GetCommands(GameState state) {
|
||||
var units = state.FindUnits();
|
||||
var neutral = state.FindFields(Owner.Neutral);
|
||||
var recyclers = state.FindFields(i => i.Recycler).Keys.ToList();
|
||||
var possibleBuilds = state.PossibleRecyclerSpots(recyclers).OrderByDescending(i => i.Value).Take(1).ToList();
|
||||
while (possibleBuilds.Count > 0) {
|
||||
var possibleBuild = possibleBuilds.First();
|
||||
if (state.MyMatter < GameState.RecyclerCost) break;
|
||||
state.MyMatter -= GameState.RecyclerCost;
|
||||
Console.Error.WriteLine($"Building recycler at {possibleBuild.Key} for {possibleBuild.Value} amount");
|
||||
yield return new Build(possibleBuild.Key);
|
||||
recyclers.Add(possibleBuild.Key);
|
||||
possibleBuilds = state.PossibleRecyclerSpots(recyclers).OrderByDescending(i => i.Value).Take(1).ToList();
|
||||
}
|
||||
foreach (var (position, amount) in units) {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
if (neutral.Count == 0) yield break;
|
||||
var emptySpot = neutral.Keys.First();
|
||||
if (!neutral.Remove(emptySpot, out var field)) throw new InvalidProgramException();
|
||||
yield return new Move(1, position, emptySpot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract record class Command {
|
||||
public virtual string GetCommandString() => $"{Name} {string.Join(' ', Args.Select(i => i.ToString()))}";
|
||||
protected virtual IEnumerable<object> Args { get; } = Enumerable.Empty<object>();
|
||||
public virtual string Name => GetType().Name.ToUpper();
|
||||
public static List<Command> Empty { get; } = new() { new Wait() };
|
||||
}
|
||||
public abstract record class CoordinateCommand(int X, int Y) : Command {
|
||||
public CoordinateCommand(Coordinate2D Coord) : this(Coord.X, Coord.Y) { }
|
||||
protected override IEnumerable<object> Args {
|
||||
get {
|
||||
yield return X;
|
||||
yield return Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
public record class Move(int Amount, int FromX, int FromY, int ToX, int ToY) : Command {
|
||||
public Move(int Amount, Coordinate2D From, Coordinate2D To) : this(Amount, From.X, From.Y, To.X, To.Y) { }
|
||||
protected override IEnumerable<object> Args {
|
||||
get {
|
||||
yield return Amount;
|
||||
yield return FromX;
|
||||
yield return FromY;
|
||||
yield return ToX;
|
||||
yield return ToY;
|
||||
}
|
||||
}
|
||||
}
|
||||
public record class Build(int X, int Y) : CoordinateCommand(X, Y) {
|
||||
public Build(Coordinate2D coord) : this(coord.X, coord.Y) { }
|
||||
}
|
||||
public record class Spawn(int Amount, int X, int Y) : CoordinateCommand(X, Y) {
|
||||
public Spawn(int Amount, Coordinate2D Coord) : this(Amount, Coord.X, Coord.Y) { }
|
||||
protected override IEnumerable<object> Args => base.Args.Prepend(Amount);
|
||||
}
|
||||
public record class Wait : Command;
|
||||
public record class Message : Command;
|
||||
public enum Owner {
|
||||
Player = 1,
|
||||
Enemy = 0,
|
||||
Neutral = -1
|
||||
}
|
||||
public record struct GameState(int Width, int Height, FieldState[,] Fields, int MyMatter = 0, int OppMatter = 0) {
|
||||
public const int RecyclerCost = 10;
|
||||
public FieldState FieldAt(Coordinate2D coord) => this[coord];
|
||||
public ref FieldState this[Coordinate2D coord] => ref Fields[coord.X, coord.Y];
|
||||
public Dictionary<Coordinate2D, int> PossibleRecyclerSpots(IReadOnlyCollection<Coordinate2D> recyclers) {
|
||||
Dictionary<Coordinate2D, int> found = new();
|
||||
for (int y = 0; y < Height; y++)
|
||||
for (int x = 0; x < Width; x++) {
|
||||
Coordinate2D coord = new(x, y);
|
||||
var field = this[coord];
|
||||
if (!field.CanBuild) continue;
|
||||
var potentialMaterial = coord.Neighbors().Append(coord)
|
||||
.Where(WithinBounds)
|
||||
.Where(i => !NearRecycler(recyclers, i))
|
||||
.Select(FieldAt)
|
||||
.Sum(i => i.ScrapAmount);
|
||||
if (potentialMaterial != 0)
|
||||
found[coord] = potentialMaterial;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
public static bool NearRecycler(IReadOnlyCollection<Coordinate2D> recyclers, Coordinate2D coord)
|
||||
=> recyclers.Any(i => (i - coord).ManhattanDistance < 2);
|
||||
|
||||
public Dictionary<Coordinate2D, int> FindWhere(Func<FieldState, int> find) {
|
||||
Dictionary<Coordinate2D, int> found = new();
|
||||
for (int y = 0; y < Height; y++)
|
||||
for (int x = 0; x < Width; x++) {
|
||||
Coordinate2D coord = new(x, y);
|
||||
var amount = find(this[coord]);
|
||||
if (amount != 0) found[coord] = found.GetValueOrDefault(coord, 0) + amount;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
public bool WithinBounds(Coordinate2D coord) => coord.X >= 0 && coord.X < Width && coord.Y >= 0 && coord.Y < Height;
|
||||
public Dictionary<Coordinate2D, FieldState> FindFields(Func<FieldState, bool> prediate) {
|
||||
Dictionary<Coordinate2D, FieldState> found = new();
|
||||
for (int y = 0; y < Height; y++)
|
||||
for (int x = 0; x < Width; x++) {
|
||||
Coordinate2D coord = new(x, y);
|
||||
var field = this[coord];
|
||||
if (prediate(field)) found[coord] = field;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
public Dictionary<Coordinate2D, FieldState> FindFields(Owner owner)
|
||||
=> FindFields(i => i.Owner == owner);
|
||||
public Dictionary<Coordinate2D, int> FindUnits(Owner owner = Owner.Player)
|
||||
=> FindWhere(i => i.Owner == owner && i is { Units: > 0 and var amount } ? amount : 0);
|
||||
|
||||
}
|
||||
public record struct Coordinate2D(int X, int Y) {
|
||||
public override string ToString() => $"{X},{Y}";
|
||||
public IEnumerable<Coordinate2D> Neighbors() {
|
||||
yield return this with { X = X + 1 };
|
||||
yield return this with { X = X - 1 };
|
||||
yield return this with { Y = Y + 1 };
|
||||
yield return this with { Y = Y - 1 };
|
||||
}
|
||||
public static Coordinate2D operator -(Coordinate2D left, Coordinate2D right) => new(left.X - right.X, left.Y - right.Y);
|
||||
public static Coordinate2D operator +(Coordinate2D left, Coordinate2D right) => new(left.X + right.X, left.Y + right.Y);
|
||||
public int ManhattanDistance => Math.Abs(X) + Math.Abs(Y);
|
||||
}
|
||||
public record struct FieldState(int ScrapAmount, Owner Owner, int Units, bool Recycler, bool CanBuild, bool CanSpawn, bool InRangeOfRecycler);
|
||||
}
|
Loading…
Reference in New Issue
Block a user