├── BackToTheCode ├── BackToTheCode.csproj ├── BackToTheCode.sln └── BackToTheCodeReferee.cs ├── CodeBusters ├── CodeBusters.csproj ├── CodeBusters.sln └── CodeBustersReferee.cs ├── GameOfDrones ├── GameOfDrones.csproj ├── GameOfDrones.sln ├── GameOfDronesReferee.cs └── test │ ├── 256965558.json │ └── test.py ├── HyperSonic ├── HyperSonic.csproj ├── HyperSonic.sln ├── HyperSonicReferee.cs └── img │ ├── Bomb1.png │ ├── Bomb2.png │ ├── Bomb3.png │ ├── Bomb4.png │ ├── Box.png │ ├── Player1.png │ ├── Player2.png │ ├── Player3.png │ ├── Player4.png │ ├── Wall.png │ ├── background.png │ ├── bombExtra.png │ └── bombRange.png ├── PokerChipRace ├── PokerChipRaceRefereeIncomplete.cs ├── pcr.gif └── readme.md ├── README.md ├── SmashTheCode ├── SmashTheCode.csproj ├── SmashTheCode.sln └── SmashTheCodeReferee.cs ├── TheGreatEscape ├── TheGreatEscape.csproj ├── TheGreatEscape.sln └── TheGreatEscapeReferee.cs └── Tron ├── Tron.csproj ├── Tron.sln └── TronReferee.cs /BackToTheCode/BackToTheCode.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | {467B8975-2AEE-4EE7-9E17-C1B7F0BAFA55} 7 | Exe 8 | BackToTheCode 9 | BackToTheCode 10 | v4.5 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug 17 | DEBUG; 18 | prompt 19 | 4 20 | true 21 | x86 22 | 23 | 24 | full 25 | true 26 | bin\Release 27 | prompt 28 | 4 29 | true 30 | x86 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /BackToTheCode/BackToTheCode.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackToTheCode", "BackToTheCode.csproj", "{467B8975-2AEE-4EE7-9E17-C1B7F0BAFA55}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {467B8975-2AEE-4EE7-9E17-C1B7F0BAFA55}.Debug|x86.ActiveCfg = Debug|x86 13 | {467B8975-2AEE-4EE7-9E17-C1B7F0BAFA55}.Debug|x86.Build.0 = Debug|x86 14 | {467B8975-2AEE-4EE7-9E17-C1B7F0BAFA55}.Release|x86.ActiveCfg = Release|x86 15 | {467B8975-2AEE-4EE7-9E17-C1B7F0BAFA55}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /BackToTheCode/BackToTheCodeReferee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | class BackToTheCodeReferee 8 | { 9 | public static void Main(string[] args) 10 | { 11 | string path = args.Length == 1 ? args [0] : null; 12 | 13 | int seed = -1; 14 | while (true) { 15 | string[] lineParts = Console.ReadLine ().Split (); 16 | if (lineParts [0] == "###Seed") 17 | seed = int.Parse (lineParts [1]); 18 | else if (lineParts [0] == "###Start") { 19 | int playerCount = int.Parse (lineParts [1]); 20 | Board board = new Board (playerCount, seed); 21 | int tick = 0; 22 | while (board.Tick ()) { 23 | tick++; 24 | if (path != null) { 25 | Bitmap bmp = board.Draw (); 26 | bmp.Save (path + System.IO.Path.DirectorySeparatorChar +$"{tick:000}.png"); 27 | bmp.Dispose (); 28 | } 29 | } 30 | Console.WriteLine (board.Ranking ()); 31 | } 32 | } 33 | } 34 | } 35 | 36 | class Board 37 | { 38 | public static readonly int MAX_ROUNDS = 200; 39 | public static readonly int WIDTH = 35; 40 | public static readonly int HEIGHT = 20; 41 | private List players = new List(); 42 | private Field[,] grid = new Field[WIDTH, HEIGHT]; 43 | List allFields = new List(); 44 | private int round = 0; 45 | 46 | public Board(int playerCount, int seed) 47 | { 48 | Random random = seed >= 0 ? new Random (seed) : new Random (); 49 | for (int i = 0; i < playerCount; i++) { 50 | players.Add(new Player(i, random.Next(WIDTH), random.Next(HEIGHT))); 51 | } 52 | for (int x = 0; x < WIDTH; x++) { 53 | for (int y = 0; y < HEIGHT; y++) { 54 | grid[x, y] = new Field(x, y); 55 | allFields.Add (grid [x, y]); 56 | } 57 | } 58 | 59 | foreach (Player p in players) { 60 | if (players.Any(q => p != q && p.X == q.X && p.Y == q.Y)) 61 | continue; 62 | grid[p.X, p.Y].Conquer(p.ID, round); 63 | } 64 | } 65 | 66 | public Bitmap Draw() { 67 | Color[] colors = new Color[] { Color.Gray, Color.Orange, Color.Red, Color.Aquamarine, Color.Purple }; 68 | Bitmap bmp = new Bitmap (20 * WIDTH, 20 * HEIGHT + 50); 69 | using (Graphics g = Graphics.FromImage (bmp)) { 70 | g.Clear (Color.Black); 71 | for (int x = 0; x < WIDTH; x++) { 72 | for (int y = 0; y < HEIGHT; y++) { 73 | using (Brush b = new SolidBrush (colors [grid [x, y].Owner + 1])) 74 | g.FillRectangle (b, 20 * x + 1, 20 * y + 1, 18, 18); 75 | } 76 | } 77 | g.FillRectangle (Brushes.Gray, 0, bmp.Height - 50, bmp.Width, 50); 78 | for (int i = 0; i < players.Count; i++) { 79 | using (Brush b = new SolidBrush (colors [i + 1])) { 80 | g.DrawString (allFields.Count (f => f.Owner == i).ToString (), 81 | new Font (new FontFamily ("Arial"), 30), 82 | b, bmp.Width / 2 + 200 * (i - players.Count / 2f), 20 * HEIGHT + 5); 83 | g.FillEllipse (b, 20 * players [i].X + 1, 20 * players [i].Y + 1, 18, 18); 84 | } 85 | g.DrawEllipse (Pens.Black, 20 * players [i].X + 1, 20 * players [i].Y + 1, 18, 18); 86 | } 87 | } 88 | return bmp; 89 | } 90 | 91 | public bool Tick() 92 | { 93 | if (++round > MAX_ROUNDS || players.Count (p => !p.Dead) < 2) { 94 | return false; 95 | } 96 | string input = this.ToString(); 97 | 98 | foreach (Player p in players.Where(pl => !pl.Dead)) { 99 | string tmp = round + "\n" + p.ToString() + "\n"; 100 | foreach (Player q in players.Where(pl => pl != p)) 101 | tmp += q.ToString () + "\n"; 102 | if (round == 1) 103 | tmp = (players.Count - 1) + "\n" + tmp; 104 | tmp += input.Replace("0", "x").Replace(p.ID.ToString(), "0").Replace("x", p.ID.ToString()); 105 | p.GetAction(tmp); 106 | } 107 | int back = players.Where(p => !p.Dead).Sum(p => p.TimeBackRound); 108 | if (back > 0) { 109 | round -= back; 110 | if (round < 0) 111 | round = 0; 112 | foreach (Player p in players.Where(p => !p.Dead)) 113 | p.Timeback(round); 114 | for (int x = 0; x < WIDTH; x++) { 115 | for (int y = 0; y < HEIGHT; y++) { 116 | grid[x, y].Timeback(round); 117 | } 118 | } 119 | } 120 | foreach (Player p in players.Where(p => !p.Dead)) { 121 | if (players.Any(q => p != q && p.X == q.X && p.Y == q.Y)) 122 | continue; 123 | if (grid[p.X, p.Y].Owner == -1) 124 | grid[p.X, p.Y].Conquer(p.ID, round); 125 | } 126 | bool[,] visited = new bool[WIDTH, HEIGHT]; 127 | for (int x = 0; x < WIDTH; x++) { 128 | for (int y = 0; y < HEIGHT; y++) { 129 | FillComponent(x, y, visited); 130 | } 131 | } 132 | return true; 133 | } 134 | 135 | public string Ranking() 136 | { 137 | int[] ids = players.Select(p => p.ID).ToArray(); 138 | int[] fields = ids.Select (id => allFields.Count (f => f.Owner == id)).ToArray (); 139 | Array.Sort(fields, ids); 140 | string result = "###End " + ids[ids.Length - 1]; 141 | for (int i = ids.Length - 2; i >= 0; i--) { 142 | if (fields[i] < fields[i + 1]) 143 | result += " "; 144 | result += ids[i]; 145 | } 146 | return result; 147 | } 148 | 149 | private static int[,] offset = new int[,] { 150 | { -1, -1 }, 151 | { -1, 0 }, 152 | { -1, 1 }, 153 | { 0, -1 }, 154 | { 0, 1 }, 155 | { 1, -1 }, 156 | { 1, 0 }, 157 | { 1, 1 } 158 | }; 159 | private void FillComponent(int x, int y, bool[,] visited) 160 | { 161 | if (visited[x, y] || grid[x, y].Owner != -1) 162 | return; 163 | List points = new List(); 164 | Stack stack = new Stack(); 165 | stack.Push(new Point(x, y)); 166 | while (stack.Count > 0) { 167 | Point p = stack.Pop(); 168 | points.Add(p); 169 | visited[p.X, p.Y] = true; 170 | for (int dir = 0; dir < 8; dir++) { 171 | Point q = new Point(p.X + offset[dir, 0], p.Y + offset[dir, 1]); 172 | if (q.X >= 0 && q.X < WIDTH && q.Y >= 0 && q.Y < HEIGHT && !visited[q.X, q.Y] && grid[q.X, q.Y].Owner == -1) 173 | stack.Push(q); 174 | } 175 | } 176 | bool[] neighbors = new bool[players.Count]; 177 | bool edge = false; 178 | foreach (Point p in points) { 179 | for (int dir = 0; dir < 8; dir++) { 180 | Point q = new Point(p.X + offset[dir, 0], p.Y + offset[dir, 1]); 181 | if (q.X < 0 || q.X >= WIDTH || q.Y < 0 || q.Y >= HEIGHT) 182 | edge = true; 183 | else if (grid[q.X, q.Y].Owner != -1) 184 | neighbors[grid[q.X, q.Y].Owner] = true; 185 | } 186 | } 187 | if (!edge && neighbors.Count(n => n) == 1) { 188 | int owner = Enumerable.Range(0, players.Count).First(o => neighbors[o]); 189 | foreach (Point p in points) 190 | grid[p.X, p.Y].Conquer(owner, round); 191 | } 192 | } 193 | 194 | public override string ToString() 195 | { 196 | StringBuilder result = new StringBuilder(); 197 | for (int y = 0; y < HEIGHT; y++) { 198 | for (int x = 0; x < WIDTH; x++) { 199 | result.Append(grid[x, y]); 200 | } 201 | result.AppendLine(); 202 | } 203 | return result.ToString(); 204 | } 205 | 206 | } 207 | 208 | class Field 209 | { 210 | public int X { get; private set; } 211 | public int Y { get; private set; } 212 | public int Owner { get; private set; } 213 | public int ConqueredRound { get; private set; } 214 | 215 | public Field(int x, int y) 216 | { 217 | this.X = x; 218 | this.Y = y; 219 | this.Owner = -1; 220 | } 221 | 222 | public void Timeback(int newRound) 223 | { 224 | if (ConqueredRound > newRound) 225 | Owner = -1; 226 | } 227 | 228 | public void Conquer(int owner, int round) 229 | { 230 | this.Owner = owner; 231 | this.ConqueredRound = round; 232 | } 233 | 234 | public override string ToString() 235 | { 236 | return Owner == -1 ? "." : Owner.ToString(); 237 | } 238 | } 239 | 240 | class Player 241 | { 242 | public static readonly int MAX_TIMEBACK = 25; 243 | public int ID { get; private set; } 244 | public int X { get; private set; } 245 | public int Y { get; private set; } 246 | public bool Dead { get; private set; } 247 | public int TimeBack { get; private set; } 248 | public int TimeBackRound { get; private set; } 249 | 250 | private List positions = new List(); 251 | public Player(int id, int x, int y) 252 | { 253 | this.ID = id; 254 | this.X = x; 255 | this.Y = y; 256 | this.TimeBack = 1; 257 | positions.Add(new Point(x, y)); 258 | } 259 | 260 | public void Timeback(int round) 261 | { 262 | positions = Enumerable.Range(0, round + 1).Select(i => positions[i]).ToList(); 263 | this.X = positions.Last().X; 264 | this.Y = positions.Last().Y; 265 | } 266 | 267 | public void GetAction(string input) 268 | { 269 | TimeBackRound = 0; 270 | Console.WriteLine("###Input " + ID); 271 | Console.Write(input); 272 | Console.WriteLine("###Output " + ID + " 1"); 273 | string action = Console.ReadLine(); 274 | string[] parts = action.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); 275 | int tmp; 276 | if (parts.Length < 2 || parts [0].ToUpper () != "BACK" && !int.TryParse (parts [0], out tmp) || !int.TryParse (parts [1], out tmp)) { 277 | Console.Error.WriteLine ("###Error " + ID + " Lost invalid input"); 278 | Dead = true; 279 | return; 280 | } 281 | int y = int.Parse(parts[1]); 282 | if (parts[0].ToUpper() == "BACK") { 283 | if (this.TimeBack > 0) { 284 | this.TimeBack--; 285 | if (y > MAX_TIMEBACK) { 286 | Console.Error.WriteLine("###Error " + ID + " Lost can't go that far back"); 287 | Dead = true; 288 | } else 289 | TimeBackRound = y; 290 | } else { 291 | Console.Error.WriteLine("###Error " + ID + " Lost no more timeback"); 292 | Dead = true; 293 | } 294 | } else { 295 | int x = int.Parse(parts[0]); 296 | if (this.X < x) 297 | this.X++; 298 | else if (this.X > x) 299 | this.X--; 300 | else if (this.Y < y) 301 | this.Y++; 302 | else if (this.Y > y) 303 | this.Y--; 304 | positions.Add(new Point(this.X, this.Y)); 305 | } 306 | } 307 | 308 | public override string ToString() 309 | { 310 | if (Dead) 311 | return "-1 -1 0"; 312 | return this.X + " " + this.Y + " " + this.TimeBack; 313 | } 314 | } -------------------------------------------------------------------------------- /CodeBusters/CodeBusters.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | {178132F0-66C4-4890-9CE6-AC9DEC3922BC} 7 | Exe 8 | CodeBusters 9 | CodeBusters 10 | v4.5 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug 17 | DEBUG; 18 | prompt 19 | 4 20 | true 21 | x86 22 | 23 | 24 | full 25 | true 26 | bin\Release 27 | prompt 28 | 4 29 | true 30 | x86 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /CodeBusters/CodeBusters.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeBusters", "CodeBusters.csproj", "{178132F0-66C4-4890-9CE6-AC9DEC3922BC}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {178132F0-66C4-4890-9CE6-AC9DEC3922BC}.Debug|x86.ActiveCfg = Debug|x86 13 | {178132F0-66C4-4890-9CE6-AC9DEC3922BC}.Debug|x86.Build.0 = Debug|x86 14 | {178132F0-66C4-4890-9CE6-AC9DEC3922BC}.Release|x86.ActiveCfg = Release|x86 15 | {178132F0-66C4-4890-9CE6-AC9DEC3922BC}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /CodeBusters/CodeBustersReferee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | 6 | class CodeBustersReferee 7 | { 8 | public static void Main(string[] args) 9 | { 10 | string path = args.Length == 1 ? args[0] : null; 11 | 12 | //read ###Start 2, as there are 2 players 13 | Console.ReadLine(); 14 | 15 | Board board = new Board(); 16 | while (board.Play()) 17 | { 18 | board.Tick(); 19 | if (path != null) { 20 | Bitmap bmp = board.Draw (); 21 | bmp.Save (path + System.IO.Path.DirectorySeparatorChar +$"{board.Round:000}.png"); 22 | bmp.Dispose (); 23 | } 24 | } 25 | board.DeclareWinner(); 26 | } 27 | 28 | class Board 29 | { 30 | public static readonly int WIDTH = 16000; 31 | public static readonly int HEIGHT = 9000; 32 | public static readonly int MAX_ROUNDS = 250; 33 | private static Random random = new Random(); 34 | private List busters = new List(); 35 | private List ghosts = new List(); 36 | public int Round { get; private set; } 37 | Player p1 = new Player(0); 38 | Player p2 = new Player(1); 39 | int bustersPreTeam = random.Next(2, 5); 40 | int ghostCount = 1 + 2 * random.Next(4, 13); 41 | 42 | public Board() 43 | { 44 | ghosts.Add(new Ghost(0, WIDTH / 2, HEIGHT / 2, random)); 45 | while(ghosts.Count < ghostCount) 46 | { 47 | int x = 0, y = 0; 48 | do 49 | { 50 | x = random.Next(WIDTH / 2); 51 | y = random.Next(HEIGHT); 52 | } while (Math.Sqrt(x * x + y * y) < 4000); 53 | Ghost g1 = new Ghost(ghosts.Count, x, y, random); 54 | ghosts.Add(g1); 55 | ghosts.Add(new Ghost(g1)); 56 | } 57 | 58 | List[] startLocations = new List[] { 59 | new List(), new List(), 60 | new List { new Point(1176, 2024), new Point(2024, 1176) }, 61 | new List { new Point(1600, 1600), new Point(2449, 751), new Point(751, 2449) }, 62 | new List { new Point(1176, 2024), new Point(2024, 1176), new Point(327, 2873), new Point(2873, 327) } 63 | }; 64 | foreach (Point p in startLocations[bustersPreTeam]) { 65 | busters.Add(new Buster(busters.Count, p.X, p.Y, p1)); 66 | } 67 | for (int i = 0; i < bustersPreTeam; i++) 68 | { 69 | busters.Add(new Buster(i + bustersPreTeam, WIDTH - busters[i].X, HEIGHT - busters[i].Y, p2)); 70 | } 71 | } 72 | 73 | public void Tick() 74 | { 75 | List actions = new List (); 76 | for (int id = 0; id <= 1; id++) { 77 | Console.WriteLine ($"###Input {id}"); 78 | List output = new List (); 79 | output.AddRange (busters.Where (b => b.Player.ID == id || b.Viewers.Any (v => v.Player.ID == id)).Select (b => b.ToString ())); 80 | output.AddRange (ghosts.Where (g => g.Viewers.Any (v => v.Player.ID == id)).Select (g => g.ToString ())); 81 | output.Insert (0, output.Count.ToString ()); 82 | if (Round == 1) { 83 | output.Insert (0, $"{bustersPreTeam}"); 84 | output.Insert (1, $"{ghostCount}"); 85 | output.Insert (2, $"{id}"); 86 | } 87 | Console.WriteLine (string.Join (Environment.NewLine, output)); 88 | Console.WriteLine ($"###Output {id} {bustersPreTeam}"); 89 | for (int i = 0; i < bustersPreTeam; i++) { 90 | actions.Add (Console.ReadLine ()); 91 | } 92 | } 93 | 94 | foreach (GameObject g in ghosts.Union(busters)) { 95 | g.PreviousViewers = g.Viewers; 96 | g.Viewers = new List (); 97 | } 98 | foreach (Ghost g in ghosts) 99 | g.Attackers.Clear (); 100 | 101 | bool[] apply = busters.Select (b => !b.IsStunned ()).ToArray (); 102 | for (int i = 0; i < busters.Count; i++) { 103 | busters [i].ApplyAction (ghosts, busters, actions [i], apply [i]); 104 | } 105 | foreach (Buster b in busters) { 106 | if (b.IsStunned () && b.BustedGhost != null) 107 | b.Release (ghosts); 108 | } 109 | 110 | for (int i = ghosts.Count - 1; i >= 0; i--) { 111 | Ghost g = ghosts [i]; 112 | if (g.Attackers.Count (a => a.Player == p1) > g.Attackers.Count (a => a.Player == p2)) 113 | CaptureGhost (g, g.Attackers.Where (a => a.Player == p1).ToList ()); 114 | if (g.Attackers.Count (a => a.Player == p1) < g.Attackers.Count (a => a.Player == p2)) 115 | CaptureGhost (g, g.Attackers.Where (a => a.Player == p2).ToList ()); 116 | if (g.Attackers.Count == 0) { //escape 117 | List closestBusters = g.PreviousViewers.OrderBy (b => b.Dist (g)).Where (b => b.Dist (g) <= Buster.BUSTER_VIEW).ToList (); 118 | if (closestBusters.Count > 0) { 119 | closestBusters = closestBusters.Where (b => b.Dist (g) == closestBusters [0].Dist (g)).ToList (); 120 | int avgX = (int)closestBusters.Average (b => b.X); 121 | int avgY = (int)closestBusters.Average (b => b.Y); 122 | g.Flee (new Point (avgX, avgY)); 123 | } 124 | } 125 | } 126 | } 127 | 128 | public Bitmap Draw() 129 | { 130 | int scaleDiv = 10; 131 | Bitmap bmp = new Bitmap (WIDTH / scaleDiv, HEIGHT / scaleDiv); 132 | using (Graphics g = Graphics.FromImage (bmp)) { 133 | g.Clear (Color.White); 134 | foreach (Buster b in busters) { 135 | if (b.IsStunned ()) 136 | g.FillEllipse (Brushes.Blue, b.X / scaleDiv - 50, b.Y / scaleDiv - 50, 100, 100); 137 | g.FillEllipse (b.Player.ID == 0 ? Brushes.Orange : Brushes.Red, b.X / scaleDiv - 30, b.Y / scaleDiv - 30, 60, 60); 138 | g.DrawEllipse (b.Player.ID == 0 ? Pens.Orange : Pens.Red, (b.X - b.ViewRange) / scaleDiv, (b.Y - b.ViewRange) / scaleDiv, 2 * b.ViewRange / scaleDiv, 2 * b.ViewRange / scaleDiv); 139 | if (b.BustedGhost != null) 140 | g.FillEllipse (Brushes.Green, b.X / scaleDiv - 15, b.Y / scaleDiv - 15, 30, 30); 141 | } 142 | foreach (Ghost ghost in ghosts) { 143 | g.FillEllipse (Brushes.Green, ghost.X / scaleDiv - 30, ghost.Y / scaleDiv - 30, 60, 60); 144 | foreach (Buster b in ghost.Attackers) 145 | g.DrawLine (Pens.Red, ghost.X / scaleDiv, ghost.Y / scaleDiv, b.X / scaleDiv, b.Y / scaleDiv); 146 | g.DrawString (ghost.Stamina.ToString (), new Font ("Arial", 12), Brushes.Black, ghost.X / scaleDiv, ghost.Y / scaleDiv); 147 | } 148 | } 149 | return bmp; 150 | } 151 | 152 | private void CaptureGhost(Ghost g, List attackers) 153 | { 154 | if (g.Stamina > 0) 155 | return; 156 | Buster b = attackers.OrderBy (a => a.Dist (g)).First (); 157 | b.BustedGhost = g; 158 | ghosts.Remove (g); 159 | } 160 | 161 | public bool Play() 162 | { 163 | return Round++ < MAX_ROUNDS && p1.CaughtGhosts * 2 < ghostCount && p2.CaughtGhosts * 2 < ghostCount; 164 | } 165 | 166 | public void DeclareWinner() 167 | { 168 | if (p1.Score(busters) > p2.Score(busters)) 169 | Console.WriteLine("###End 0 1"); 170 | else if (p1.Score(busters) < p2.Score(busters)) 171 | Console.WriteLine("###End 1 0"); 172 | else 173 | Console.WriteLine("###End 01"); 174 | } 175 | } 176 | 177 | class Buster : GameObject 178 | { 179 | public static readonly int BUSTER_MAX_DIST = 800; 180 | public static readonly int BUSTER_VIEW = 2200; 181 | public static readonly int BUSTER_RADAR = 4400; 182 | public static readonly int BUSTER_MAX_STUN_RANGE = 1760; 183 | public static readonly int BUSTER_STUN_COOLDOWN = 20; 184 | public static readonly int BUSTER_STUN_HIT = 10; 185 | public static readonly int BUSTER_MIN_BUST = 900; 186 | public static readonly int BUSTER_MAX_BUST = 1760; 187 | public static readonly int BUSTER_MAX_EJECT = 1760; 188 | public static readonly int BUSTER_RELEASE_RANGE = 1600; 189 | 190 | public Ghost BustedGhost { get; set; } 191 | public Player Player { get; private set; } 192 | public int ViewRange { get; private set; } 193 | private int cooldownTime = 0; 194 | private int stunnedTime = 0; 195 | private bool canRadar = true; 196 | public Buster(int id, int x, int y, Player player) : base(id, x, y) { this.Player = player; } 197 | 198 | public bool IsStunned() 199 | { 200 | return stunnedTime > 0; 201 | } 202 | 203 | public void ApplyAction(List ghosts, List busters, string action, bool apply) 204 | { 205 | string[] parts = action.Split (" ".ToCharArray (), StringSplitOptions.RemoveEmptyEntries); 206 | ViewRange = BUSTER_VIEW; 207 | if (cooldownTime > 0) 208 | cooldownTime--; 209 | if (stunnedTime > 0) 210 | stunnedTime--; 211 | if (apply) {// buster is not stunned 212 | switch (parts [0].ToUpper ()) { 213 | case "MOVE": 214 | this.Move (new Point (int.Parse (parts [1]), int.Parse (parts [2]))); 215 | break; 216 | case "BUST": 217 | DropGhost (ghosts); 218 | Ghost ghost = ghosts.FirstOrDefault (g => g.ID == int.Parse (parts [1])); 219 | if (ghost != null && this.Dist (ghost) >= BUSTER_MIN_BUST && this.Dist (ghost) <= BUSTER_MAX_BUST) { 220 | ghost.Attack (this); 221 | } 222 | break; 223 | case "RELEASE": 224 | Release (ghosts); 225 | break; 226 | case "STUN": 227 | DropGhost (ghosts); 228 | Buster target = busters.FirstOrDefault (b => b.ID == int.Parse (parts [1])); 229 | if (cooldownTime == 0 && this.Dist (target) <= BUSTER_MAX_STUN_RANGE) { 230 | target.stunnedTime = BUSTER_STUN_HIT; 231 | if (target.ID > this.ID) 232 | target.stunnedTime++; //will be reduced during target.ApplyAction 233 | this.cooldownTime = BUSTER_STUN_COOLDOWN; 234 | } 235 | break; 236 | case "RADAR": 237 | if (canRadar) { 238 | canRadar = false; 239 | ViewRange = BUSTER_RADAR; 240 | } 241 | break; 242 | case "EJECT": 243 | DropGhost (ghosts)?.MoveTo (new Point (int.Parse (parts [1]), int.Parse (parts [2])), BUSTER_MAX_EJECT); 244 | break; 245 | } 246 | } 247 | foreach (GameObject g in ghosts.Union(busters)) { 248 | if (this.Dist (g) <= ViewRange) 249 | g.See (this); 250 | } 251 | } 252 | 253 | private void Move(Point target) => MoveTo(target, BUSTER_MAX_DIST); 254 | 255 | private Ghost DropGhost(List ghosts) 256 | { 257 | if (BustedGhost != null) { 258 | Ghost g = BustedGhost; 259 | ghosts.Add (g); 260 | g.X = this.X; 261 | g.Y = this.Y; 262 | g.Attackers.Clear (); 263 | BustedGhost = null; 264 | return g; 265 | } 266 | return null; 267 | } 268 | 269 | public void Release(List ghosts) 270 | { 271 | if (BustedGhost == null) 272 | return; 273 | if (this.Dist (Player.BaseLocation) <= BUSTER_RELEASE_RANGE) 274 | Player.ScorePoint (); 275 | else { 276 | BustedGhost.X = this.X; 277 | BustedGhost.Y = this.Y; 278 | BustedGhost.Attackers.Clear (); 279 | ghosts.Add (BustedGhost); 280 | } 281 | 282 | BustedGhost = null; 283 | } 284 | 285 | public override string ToString() 286 | { 287 | int state = 0; 288 | if (BustedGhost != null) 289 | state = 1; 290 | if (IsStunned ()) 291 | state = 2; 292 | int value = -1; 293 | if (BustedGhost != null) 294 | value = BustedGhost.ID; 295 | return $"{ID} {X} {Y} {Player.ID} {state} {value}"; 296 | } 297 | } 298 | 299 | class Player 300 | { 301 | public int ID { get; private set; } 302 | public GameObject BaseLocation; 303 | public int CaughtGhosts { get; private set; } 304 | 305 | public Player(int id) 306 | { 307 | this.ID = id; 308 | if (id == 0) BaseLocation = new GameObject(0, 0, 0); 309 | else BaseLocation = new GameObject(0, Board.WIDTH, Board.HEIGHT); 310 | } 311 | 312 | public int Score(List busters) 313 | { 314 | return CaughtGhosts + busters.Count(b => b.Player == this && b.BustedGhost != null); 315 | } 316 | 317 | public void ScorePoint() 318 | { 319 | CaughtGhosts++; 320 | } 321 | } 322 | 323 | class Ghost : GameObject 324 | { 325 | public static readonly int ESCAPE_SPEED = 400; 326 | 327 | public int Stamina { get; set; } 328 | public List Attackers = new List(); 329 | private static readonly int[] STAMINA = new int[] { 3, 15, 40 }; 330 | 331 | 332 | public Ghost(int id, int x, int y, Random random) : base(id, x, y) 333 | { 334 | Stamina = STAMINA[random.Next(STAMINA.Length)]; 335 | } 336 | 337 | public Ghost(Ghost g) : base(g.ID + 1, Board.WIDTH - g.X, Board.HEIGHT - g.Y) 338 | { 339 | this.Stamina = g.Stamina; 340 | } 341 | 342 | public void Attack(Buster b) 343 | { 344 | Attackers.Add(b); 345 | Stamina = Math.Max(0, Stamina - 1); 346 | } 347 | 348 | public void Flee(Point p) { 349 | int targetX = this.X + ESCAPE_SPEED * (this.X - p.X); 350 | int targetY = this.Y + ESCAPE_SPEED * (this.Y - p.Y); 351 | MoveTo (new Point (targetX, targetY), ESCAPE_SPEED); 352 | } 353 | 354 | public override string ToString() 355 | { 356 | return $"{ID} {X} {Y} -1 {Stamina} {Attackers.Count}"; 357 | } 358 | } 359 | 360 | 361 | class GameObject 362 | { 363 | public int X { get; set; } 364 | public int Y { get; set; } 365 | public int ID { get; private set; } 366 | public List Viewers = new List(); 367 | public List PreviousViewers = new List(); 368 | public GameObject(int id, int x, int y) 369 | { 370 | this.ID = id; 371 | this.X = x; 372 | this.Y = y; 373 | } 374 | 375 | public void MoveTo(Point target, int dist) 376 | { 377 | double dx = target.X - this.X; 378 | double dy = target.Y - this.Y; 379 | double d = Math.Sqrt (dx * dx + dy * dy); 380 | if (d <= dist) { 381 | this.X = target.X; 382 | this.Y = target.Y; 383 | } else { 384 | this.X = (int)Math.Round (this.X + dist * dx / d); 385 | this.Y = (int)Math.Round (this.Y + dist * dy / d); 386 | } 387 | ResetInBoard (); 388 | } 389 | 390 | private void ResetInBoard() 391 | { 392 | if (X < 0) 393 | X = 0; 394 | if (X > Board.WIDTH) 395 | X = Board.WIDTH; 396 | if (Y < 0) 397 | Y = 0; 398 | if (Y > Board.HEIGHT) 399 | Y = Board.HEIGHT; 400 | } 401 | 402 | public double Dist(GameObject other) 403 | { 404 | double dx = this.X - other.X; 405 | double dy = this.Y - other.Y; 406 | return Math.Sqrt(dx * dx + dy * dy); 407 | } 408 | 409 | public void See(Buster b) 410 | { 411 | Viewers.Add(b); 412 | } 413 | } 414 | } 415 | -------------------------------------------------------------------------------- /GameOfDrones/GameOfDrones.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | {0DDB8615-7534-4703-9FD1-713B7E2BC08F} 7 | Exe 8 | GameOfDrones 9 | GameOfDrones 10 | v4.5 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug 17 | DEBUG; 18 | prompt 19 | 4 20 | true 21 | x86 22 | 23 | 24 | full 25 | true 26 | bin\Release 27 | prompt 28 | 4 29 | true 30 | x86 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /GameOfDrones/GameOfDrones.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameOfDrones", "GameOfDrones.csproj", "{0DDB8615-7534-4703-9FD1-713B7E2BC08F}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {0DDB8615-7534-4703-9FD1-713B7E2BC08F}.Debug|x86.ActiveCfg = Debug|x86 13 | {0DDB8615-7534-4703-9FD1-713B7E2BC08F}.Debug|x86.Build.0 = Debug|x86 14 | {0DDB8615-7534-4703-9FD1-713B7E2BC08F}.Release|x86.ActiveCfg = Release|x86 15 | {0DDB8615-7534-4703-9FD1-713B7E2BC08F}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /GameOfDrones/GameOfDronesReferee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Drawing; 5 | using System.IO; 6 | 7 | public class GameOfDronesReferee 8 | { 9 | static readonly int WIDTH = 4000; 10 | static readonly int HEIGHT = 1800; 11 | static readonly int ROUNDS = 200; 12 | static readonly int ZONE_SIZE = 100; 13 | static readonly int DRONE_SPEED = 100; 14 | static readonly int MIN_DRONES = 3; 15 | static readonly int MAX_DRONES = 11; 16 | 17 | public static void Main(string[] args) 18 | { 19 | string path = args.Length == 1 ? args [0] : null; 20 | Board board = null; 21 | while (true) { 22 | string inputLine = Console.ReadLine (); 23 | if (inputLine.StartsWith ("###Map")) { 24 | board = new Board (); 25 | } else if (inputLine.StartsWith ("###Start")) { 26 | int playerCount = int.Parse (inputLine.Split () [1]); 27 | if (board == null) 28 | board = new Board (playerCount); 29 | while (board.Play (path)) 30 | ; 31 | if (path != null) { 32 | Bitmap bmp = board.Draw (); 33 | bmp.Save (path + Path.DirectorySeparatorChar +$"{ROUNDS:000}.png"); 34 | bmp.Dispose (); 35 | } 36 | 37 | Console.WriteLine (board.DeclareWinner ()); 38 | return; 39 | } 40 | } 41 | } 42 | 43 | class Board { 44 | private int playerCount; 45 | private int droneCount; 46 | private List zones = new List(); 47 | private List drones = new List(); 48 | private int[] scores; 49 | private int round = 0; 50 | 51 | public Board() { 52 | int[] nums = Console.ReadLine ().Split (' ').Select (int.Parse).ToArray (); 53 | playerCount = nums[0]; 54 | droneCount = nums[2]; 55 | int zoneCount = nums[3]; 56 | for (int i = 0; i < zoneCount; i++) { 57 | nums = Console.ReadLine ().Split (' ').Select (int.Parse).ToArray (); 58 | zones.Add(new Zone(nums[0], nums[1])); 59 | } 60 | for (int i = 0; i < zoneCount; i++) { 61 | Console.ReadLine(); 62 | } 63 | for (int p = 0; p < playerCount; p++) { 64 | for (int d = 0; d < droneCount; d++) { 65 | nums = Console.ReadLine ().Split (' ').Select (int.Parse).ToArray (); 66 | drones.Add(new Drone(nums[0], nums[1], p)); 67 | } 68 | } 69 | scores = new int[playerCount]; 70 | } 71 | 72 | public Board(int playerCount) { 73 | if (this.playerCount > 0) return; //already loaded a map 74 | this.playerCount = playerCount; 75 | Random random = new Random (); 76 | int zoneCount = 2 * playerCount; 77 | for (int i = 0; i < zoneCount; i++) { 78 | Point p = new Point (); 79 | do { 80 | p = new Point (random.Next (WIDTH), random.Next (HEIGHT)); 81 | } while (zones.Any (z => Math.Sqrt ((z.X - p.X) * (z.X - p.X) + (z.Y - p.Y) * (z.Y - p.Y)) < 700)); 82 | zones.Add (new Zone (p.X, p.Y)); 83 | } 84 | 85 | droneCount = 1 + random.Next (MIN_DRONES, MAX_DRONES); 86 | for (int j = 0; j < droneCount; j++) { 87 | drones.Add (new Drone (random.Next (WIDTH), random.Next (HEIGHT), 0)); 88 | } 89 | for (int i = 1; i < playerCount; i++) { 90 | for (int j = 0; j < droneCount; j++) { 91 | drones.Add (new Drone (drones [j].X, drones [j].Y, i)); 92 | } 93 | } 94 | scores = new int[playerCount]; 95 | } 96 | 97 | public bool Play(string path) { 98 | List input = zones.Select (z => $"{z.Owner}").ToList (); 99 | input.AddRange (drones.Select (d => d.ToString())); 100 | if (path != null) { 101 | Bitmap bmp = Draw (); 102 | bmp.Save (path + Path.DirectorySeparatorChar +$"{round:000}.png"); 103 | bmp.Dispose (); 104 | 105 | using (StreamWriter sw = new StreamWriter ($"{round:000}.txt")) { 106 | sw.WriteLine ($"{playerCount} {0} {droneCount} {zones.Count}"); 107 | foreach (Zone z in zones) 108 | sw.WriteLine ($"{z.X} {z.Y}"); 109 | foreach (string line in input) 110 | sw.WriteLine (line); 111 | } 112 | } 113 | List actions = new List (); 114 | for (int p = 0; p < playerCount; p++) { 115 | Console.WriteLine ("###Input " + p); 116 | if (round == 0) { 117 | Console.WriteLine ($"{playerCount} {p} {droneCount} {zones.Count}"); 118 | foreach (Zone z in zones) 119 | Console.WriteLine ($"{z.X} {z.Y}"); 120 | } 121 | foreach (string line in input) 122 | Console.WriteLine (line); 123 | Console.WriteLine ($"###Output {p} {droneCount}"); 124 | for (int l = 0; l < droneCount; l++) { 125 | actions.Add (Console.ReadLine ()); 126 | } 127 | } 128 | for (int j = 0; j < drones.Count; j++) { 129 | string[] parts = actions [j].Split (" ".ToCharArray (), StringSplitOptions.RemoveEmptyEntries); 130 | drones [j].Move (int.Parse (parts [0]), int.Parse (parts [1])); 131 | } 132 | 133 | foreach (Zone z in zones) { 134 | int maxCount = 0; 135 | List maxIndex = new List (); 136 | for (int p = 0; p < playerCount; p++) { 137 | if (maxCount < drones.Count (d => d.Owner == p && z.IsInZone (d))) { 138 | maxCount = drones.Count (d => d.Owner == p && z.IsInZone (d)); 139 | maxIndex.Clear (); 140 | } 141 | if (maxCount == drones.Count (d => d.Owner == p && z.IsInZone (d))) 142 | maxIndex.Add (p); 143 | } 144 | if (maxIndex.Count == 1) 145 | z.Owner = maxIndex [0]; 146 | } 147 | for (int j = 0; j < playerCount; j++) { 148 | scores [j] += zones.Count (z => z.Owner == j); 149 | } 150 | round++; 151 | return round < 200; 152 | } 153 | 154 | public Bitmap Draw() 155 | { 156 | Color[] colors = { Color.Gray, Color.Orange, Color.Red, Color.Aquamarine, Color.Purple }; 157 | Bitmap bmp = new Bitmap(WIDTH, HEIGHT + 50); 158 | using (Graphics g = Graphics.FromImage(bmp)) 159 | { 160 | g.Clear(Color.White); 161 | foreach (Zone z in zones) 162 | { 163 | using (Brush b = new SolidBrush(colors[z.Owner + 1])) 164 | g.FillEllipse(b, z.X - 100, z.Y - 100, 200, 200); 165 | } 166 | foreach (Drone d in drones) 167 | { 168 | using (Brush b = new SolidBrush(colors[d.Owner + 1])) 169 | g.FillEllipse(b, (float)d.X - 30, (float)d.Y - 30, 60, 60); 170 | g.DrawEllipse(Pens.Black, (float)d.X - 30, (float)d.Y - 30, 60, 60); 171 | } 172 | g.FillRectangle(Brushes.Gray, 0, HEIGHT, WIDTH, 50); 173 | for (int i = 0; i < scores.Length; i++) 174 | { 175 | using (Brush b = new SolidBrush(colors[i + 1])) 176 | g.DrawString(scores[i].ToString(), new Font(new FontFamily("Arial"), 30), b, WIDTH / 2 + 200 * (i - scores.Length / 2f), HEIGHT + 5); 177 | } 178 | } 179 | return bmp; 180 | } 181 | 182 | public string DeclareWinner() { 183 | int[] ids = Enumerable.Range (0, playerCount).ToArray (); 184 | Array.Sort (scores, ids); 185 | string result = "###End " + ids [playerCount - 1]; 186 | for (int i = playerCount - 2; i >= 0; i--) { 187 | if (scores [i + 1] > scores [i]) 188 | result += " "; 189 | result += ids [i]; 190 | } 191 | return result; 192 | } 193 | } 194 | 195 | class Zone 196 | { 197 | public int X { get; private set; } 198 | public int Y { get; private set; } 199 | public int Owner { get; set; } = -1; 200 | 201 | public Zone(int x, int y) 202 | { 203 | this.X = x; 204 | this.Y = y; 205 | } 206 | 207 | public bool IsInZone(Drone d) 208 | { 209 | double dx = Math.Abs(this.X - d.X); 210 | double dy = Math.Abs(this.Y - d.Y); 211 | return dx * dx + dy * dy <= ZONE_SIZE * ZONE_SIZE; 212 | } 213 | } 214 | 215 | class Drone 216 | { 217 | public double X { get; private set; } 218 | public double Y { get; private set; } 219 | public int Owner { get; private set; } 220 | 221 | public Drone(double x, double y, int owner) 222 | { 223 | this.X = x; 224 | this.Y = y; 225 | this.Owner = owner; 226 | } 227 | 228 | public void Move(int targetX, int targetY) 229 | { 230 | double dx = targetX - X; 231 | double dy = targetY - Y; 232 | double dist = Math.Sqrt(dx * dx + dy * dy); 233 | if (dist <= DRONE_SPEED) 234 | { 235 | this.X = targetX; 236 | this.Y = targetY; 237 | return; 238 | } 239 | this.X += dx / dist * DRONE_SPEED; 240 | this.Y += dy / dist * DRONE_SPEED; 241 | } 242 | 243 | public override string ToString () 244 | { 245 | return Math.Round(X) + " " + Math.Round(Y); 246 | } 247 | } 248 | } -------------------------------------------------------------------------------- /GameOfDrones/test/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os, json 4 | 5 | player_count = 0 6 | zones = [] 7 | drone_count = 0 8 | 9 | def parse_frame(frames, index): 10 | global player_count, zones, drone_count 11 | 12 | frame = frames[index] 13 | view = frame['view'].strip('\n').split('\n') 14 | turn = int(view[0]) 15 | if turn == 0: 16 | player_count, _, drone_count, zone_count = map(int, view[3].split()) 17 | zones = view[4:4+zone_count] 18 | view = view[4 + zone_count:] 19 | else: 20 | view = view[1:] 21 | 22 | stdin = ['###Input ' + str((frame['agentId']+1)%player_count)] 23 | if index < player_count: 24 | stdin.append('{} {} {} {}'.format(player_count, (frame['agentId']+1)%player_count, drone_count, len(zones))) 25 | for zone in zones: stdin.append(zone) 26 | for i in range(len(zones)): 27 | stdin.append(view[player_count + i*(player_count+1)]) # get the owners, skip how many drones are in a zone 28 | view = view[(player_count+1) * len(zones) + player_count:] 29 | for drone in view: 30 | stdin.append(' '.join(drone.split()[:2])) 31 | 32 | if 'stdout' in frame: 33 | stdout = frame['stdout'].strip('\n').split('\n') 34 | if index > 0: 35 | stdin.insert(0, '###Output {} {}'.format(frame['agentId'], drone_count)) 36 | if 'stdout' not in frame: 37 | stdout = ['###Map'] 38 | for i in stdin: 39 | if '###' not in i: stdout.append(i) 40 | stdout.append('###Start ' + str(player_count)) 41 | return {'stdin':stdin, 'stdout':stdout} 42 | 43 | 44 | for filename in [pos_json for pos_json in os.listdir('.') if pos_json.endswith('.json')]: 45 | with open(filename, 'r') as f: 46 | data = json.load(f) 47 | frames = data['success']['frames'] 48 | initial = parse_frame(frames, 0) 49 | if len(frames) != 200 * player_count + 1: 50 | continue # my referee doesn't handle crashing players, just go on with the next testfile 51 | 52 | with open(os.path.splitext(filename)[0] + '.in', 'w') as stdin, \ 53 | open(os.path.splitext(filename)[0] + '.out', 'w') as stdout: 54 | for index in range(len(frames)): 55 | for text in parse_frame(frames, index)['stdin']: 56 | stdin.write(text + '\n') 57 | for text in parse_frame(frames, index)['stdout']: 58 | stdout.write(text + '\n') 59 | 60 | # compare files to check correctness: 61 | # e.g. ./GameOfDrones.exe < 256965558.out > mySim.in && diff 256965558.in mySim.in 62 | # there are a few differences when a drone has a distance of nearly exactly 100 => rounding errors 63 | 64 | -------------------------------------------------------------------------------- /HyperSonic/HyperSonic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | {7EE62614-9754-4517-A0DE-303E8632CC8B} 7 | Exe 8 | HyperSonic 9 | HyperSonic 10 | v4.5 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug 17 | DEBUG; 18 | prompt 19 | 4 20 | true 21 | x86 22 | 23 | 24 | full 25 | true 26 | bin\Release 27 | prompt 28 | 4 29 | true 30 | x86 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | PreserveNewest 47 | 48 | 49 | PreserveNewest 50 | 51 | 52 | PreserveNewest 53 | 54 | 55 | PreserveNewest 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | PreserveNewest 62 | 63 | 64 | PreserveNewest 65 | 66 | 67 | PreserveNewest 68 | 69 | 70 | PreserveNewest 71 | 72 | 73 | PreserveNewest 74 | 75 | 76 | PreserveNewest 77 | 78 | 79 | PreserveNewest 80 | 81 | 82 | PreserveNewest 83 | 84 | 85 | -------------------------------------------------------------------------------- /HyperSonic/HyperSonic.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HyperSonic", "HyperSonic.csproj", "{7EE62614-9754-4517-A0DE-303E8632CC8B}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {7EE62614-9754-4517-A0DE-303E8632CC8B}.Debug|x86.ActiveCfg = Debug|x86 13 | {7EE62614-9754-4517-A0DE-303E8632CC8B}.Debug|x86.Build.0 = Debug|x86 14 | {7EE62614-9754-4517-A0DE-303E8632CC8B}.Release|x86.ActiveCfg = Release|x86 15 | {7EE62614-9754-4517-A0DE-303E8632CC8B}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /HyperSonic/HyperSonicReferee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | 9 | class JavaRandom { 10 | public uint next(uint bits) 11 | { 12 | seed = (seed * 0x5DEECE66DLL + 0xBLL) & ((1LL << 48) - 1); 13 | return (uint)(seed >> (int)(48 - bits)); 14 | } 15 | 16 | ulong seed; 17 | 18 | public static ulong CurrentTimeMillis() 19 | { 20 | DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 21 | return (ulong) (DateTime.UtcNow - Jan1st1970).TotalMilliseconds; 22 | } 23 | public void setSeed(ulong _seed) 24 | { 25 | seed = (_seed ^ 0x5DEECE66DLL) & ((1LL << 48) - 1); 26 | } 27 | public JavaRandom() 28 | { 29 | setSeed(CurrentTimeMillis()); 30 | } 31 | public JavaRandom(ulong _seed) 32 | { 33 | setSeed(_seed); 34 | } 35 | public int nextInt() 36 | { 37 | return (int)next(32); 38 | } 39 | 40 | public int nextInt(int n) 41 | { 42 | if ((n & -n) == n) // i.e., n is a power of 2 43 | return (int)(((ulong)n * (ulong)next(31)) >> 31); 44 | int bits, val; 45 | do 46 | { 47 | bits = (int)next(31); 48 | val = bits % n; 49 | } while (bits - val + (n - 1) < 0); 50 | return val; 51 | } 52 | public long nextLong() 53 | { 54 | return (long)(((ulong)next(32) << 32) + (ulong)next(32)); 55 | } 56 | public bool nextBoolean() 57 | { 58 | return next(1) != 0; 59 | } 60 | 61 | }; 62 | 63 | 64 | class Referee 65 | { 66 | public static int[,] Offset = new int[,] { 67 | { 0, 1 }, 68 | { 0, -1 }, 69 | { 1, 0 }, 70 | { -1, 0 } 71 | }; 72 | public static List Players; 73 | public static void Main(string[] args) 74 | { 75 | string path = args.Length == 1 ? args[0] : null; 76 | int players =2; 77 | string start = Console.ReadLine (); 78 | JavaRandom random = new JavaRandom(); 79 | ulong seed = (ulong)random.nextInt(999999999); 80 | try { 81 | if (start.StartsWith("###Seed")) { 82 | seed = ulong.Parse( start.Substring(8)); 83 | Console.Error.WriteLine("Using seed:"+seed); 84 | random = new JavaRandom(seed); 85 | start = Console.ReadLine (); 86 | } 87 | players = int.Parse (start.Split () [1]); 88 | } catch (Exception e) { 89 | Console.Error.WriteLine ("Invalid parameter '"+start+"': "+e); 90 | return; 91 | } 92 | 93 | Board board = new Board(random, players); 94 | Players = board.players; 95 | int round = 0; 96 | while (board.Play()) { 97 | Console.Error.WriteLine (path); 98 | board.Tick(); 99 | round++; 100 | if (path != null) 101 | { 102 | Console.Error.WriteLine ("draw " + round); 103 | Bitmap bmp = board.Draw (); 104 | bmp.Save(path + System.IO.Path.DirectorySeparatorChar + $"{round:000}.png"); 105 | bmp.Dispose(); 106 | } 107 | } 108 | List ranking = board.players.OrderByDescending(p => p.Score).ToList(); 109 | string result = "###End " + ranking[0].ID; 110 | for (int i = 1; i < ranking.Count; i++) { 111 | if (ranking[i - 1].Score > ranking[i].Score) 112 | result += " "; 113 | result += ranking[i].ID; 114 | } 115 | Console.WriteLine(result); 116 | } 117 | } 118 | 119 | class Player 120 | { 121 | public int ID { get; private set; } 122 | public int Score { get; set; } 123 | public Field Location { get; set; } 124 | public Field NewLocation { get; private set; } 125 | public bool PlaceBomb { get; private set; } 126 | public bool Dead { get; set; } 127 | public int BombFree { get; set; } 128 | public int BombRange { get; set; } 129 | 130 | public Player(int id, Board board) 131 | { 132 | this.ID = id; 133 | this.BombFree = 1; 134 | this.BombRange = 3; 135 | switch (id) { 136 | case 0: 137 | Location = board.Grid[0, 0]; 138 | break; 139 | case 1: 140 | Location = board.Grid[Board.WIDTH - 1, Board.HEIGHT - 1]; 141 | break; 142 | case 2: 143 | Location = board.Grid[Board.WIDTH - 1, 0]; 144 | break; 145 | case 3: 146 | Location = board.Grid[0, Board.HEIGHT - 1]; 147 | break; 148 | } 149 | } 150 | 151 | public void GetAction(string input) 152 | { 153 | Console.WriteLine("###Output " + ID + " 1"); 154 | string[] line = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); 155 | int tmp; 156 | if (line.Length < 3 || line[0].ToUpper() != "MOVE" && line[0].ToUpper() != "BOMB" || !int.TryParse(line[1], out tmp) || !int.TryParse(line[2], out tmp)) { 157 | Console.Error.WriteLine ("###Error " + ID + " Lost invalid command: '" + string.Join (" ", line) + "'"); 158 | Dead = true; 159 | return; 160 | } 161 | 162 | PlaceBomb = line[0].ToUpper() == "BOMB" && this.BombFree > 0 && Location.Bombs.Count == 0; 163 | int x = int.Parse(line[1]); 164 | int y = int.Parse(line[2]); 165 | if (x < 0 || x >= Board.WIDTH || y < 0 || y >= Board.HEIGHT) { 166 | Console.Error.WriteLine ("###Error " + ID + " Lost invalid target: " + x + "/" + y); 167 | Dead = true; 168 | return; 169 | } 170 | 171 | int distToTarget = Math.Abs(x - Location.X) + Math.Abs(y - Location.Y); 172 | NewLocation = Location; 173 | for (int dir = 0; dir < 4; dir++) { 174 | Field test = Location.Neighbors[dir]; 175 | if (test != null && Math.Abs(x - test.X) + Math.Abs(y - test.Y) < distToTarget && !test.Box && !test.Wall && test.Bombs.Count == 0) { 176 | NewLocation = test; 177 | break; 178 | } 179 | } 180 | } 181 | 182 | public override string ToString() 183 | { 184 | return "0 " + ID + " " + Location.X + " " + Location.Y + " " + BombFree + " " + BombRange; 185 | } 186 | } 187 | 188 | class Board 189 | { 190 | public static readonly int MAX_ROUNDS = 200; 191 | public static readonly int ROUNDS_AFTER_LAST_BOX = 20; 192 | public static readonly int WIDTH = 13; 193 | public static readonly int HEIGHT = 11; 194 | public static readonly int MIN_BOXES = 30; 195 | public static readonly int MAX_BOXES = 65; 196 | public Field[,] Grid { get; private set; } 197 | public List players = new List(); 198 | private List allFields = new List(); 199 | 200 | public bool Play() 201 | { 202 | return players.Count(p => !p.Dead) > 1 && round < MAX_ROUNDS; 203 | } 204 | 205 | public Board(JavaRandom random, int playerCount) 206 | { 207 | Grid = new Field[WIDTH, HEIGHT]; 208 | for (int x = 0; x < WIDTH; x++) { 209 | for (int y = 0; y < HEIGHT; y++) { 210 | Grid[x, y] = new Field(x, y); 211 | allFields.Add(Grid[x, y]); 212 | } 213 | } 214 | foreach (Field f in allFields) { 215 | f.InitNeighbors(Grid); 216 | } 217 | for (int i = 0; i < playerCount; i++) { 218 | players.Add(new Player(i, this)); 219 | } 220 | 221 | int boxCount = 30 + random.nextInt(36); 222 | int[] toDistribute = new int[2]{boxCount / 3,boxCount / 3}; 223 | 224 | List startingPositions = new List(){Grid[0,0],Grid[0,HEIGHT-1],Grid[WIDTH-1,HEIGHT-1],Grid[WIDTH-1,0]}; 225 | 226 | int iterations = 0; 227 | int boxId = 0; 228 | while (boxId < boxCount) { 229 | iterations++; 230 | 231 | if (iterations > 1000) { 232 | break; 233 | } 234 | 235 | int x = random.nextInt(WIDTH); 236 | int y = random.nextInt(HEIGHT); 237 | 238 | bool ok = true; 239 | foreach (var p in startingPositions) { 240 | if ((Math.Abs(p.X - x) + Math.Abs(p.Y - y)) < 2) 241 | { 242 | ok = false; 243 | break; 244 | } 245 | } 246 | if (!ok) continue; 247 | if (Grid[x, y].Wall || Grid[x, y].Box) 248 | continue; 249 | 250 | Grid[x, y].Box = true; 251 | for (int i=0;i<2;++i){ 252 | if (toDistribute[i] >0) 253 | { 254 | Grid[x, y].PowerUp = new PowerUp { ExtraRange = (i==0),ExtraBomb = (i!=0), field = Grid[x, y] }; 255 | --toDistribute[i]; 256 | break; 257 | } 258 | } 259 | 260 | 261 | ++boxId; 262 | List otherCells = new List(){ Grid[WIDTH - x - 1,y ],Grid[WIDTH - x - 1,HEIGHT - y - 1],Grid[x,HEIGHT - y - 1]}; 263 | foreach (var c in otherCells){ 264 | if (!c.Wall && !c.Box) 265 | { 266 | c.Box = true; 267 | ++boxId; 268 | if (Grid[x, y].PowerUp != null) 269 | { 270 | c.PowerUp = new PowerUp { ExtraRange = Grid[x, y].PowerUp.ExtraRange,ExtraBomb = Grid[x, y].PowerUp.ExtraBomb, field = c }; 271 | --toDistribute[c.PowerUp.ExtraRange?0:1]; 272 | } 273 | } 274 | } 275 | } 276 | } 277 | 278 | public Bitmap Draw() { 279 | Bitmap bmp = (Bitmap)Bitmap.FromFile ("img" + Path.DirectorySeparatorChar + "background.png"); 280 | using (Graphics g = Graphics.FromImage (bmp)) { 281 | for (int x = 0; x < WIDTH; x++) { 282 | for (int y = 0; y < HEIGHT; y++) { 283 | if (Grid [x, y].Wall) 284 | g.DrawImage (Bitmap.FromFile ("img" + Path.DirectorySeparatorChar + "Wall.png"), 700 + 90 * x, 43 + 90 * y); 285 | if (Grid[x,y].Box) 286 | g.DrawImage (Bitmap.FromFile ("img" + Path.DirectorySeparatorChar + "Box.png"), 700 + 90 * x, 43 + 90 * y); 287 | if (Grid[x,y].PowerUp != null && Grid[x,y].PowerUp.ExtraBomb) 288 | g.DrawImage (Bitmap.FromFile ("img" + Path.DirectorySeparatorChar + "bombExtra.png"), 712 + 90 * x, 55 + 90 * y); 289 | if (Grid[x,y].PowerUp != null && Grid[x,y].PowerUp.ExtraRange) 290 | g.DrawImage (Bitmap.FromFile ("img" + Path.DirectorySeparatorChar + "bombRange.png"), 712 + 90 * x, 55 + 90 * y); 291 | if (Grid [x, y].Bombs.Count > 0) 292 | g.DrawImage (Bitmap.FromFile ("img" + Path.DirectorySeparatorChar + "Bomb" + (Grid [x, y].Bombs.First ().Owner.ID + 1) + ".png"), 710 + 90 * x, 48 + 90 * y); 293 | } 294 | } 295 | foreach (Player p in players) { 296 | g.DrawImage (Bitmap.FromFile ("img" + Path.DirectorySeparatorChar + "Player" + (p.ID + 1) + ".png"), 705 + 90 * p.Location.X, 48 + 90 * p.Location.Y); 297 | } 298 | } 299 | return bmp; 300 | } 301 | 302 | private int round = 0; 303 | public void Tick() 304 | { 305 | round++; 306 | 307 | //ask players for next action 308 | string input = this.ToString(); 309 | foreach (Player p in players.Where(p => !p.Dead)) { 310 | Console.WriteLine("###Input " + p.ID); 311 | if (round == 1) 312 | Console.WriteLine(WIDTH + " " + HEIGHT + " " + p.ID); 313 | Console.Write(input); 314 | p.GetAction(input); 315 | } 316 | 317 | //make bombs explode 318 | foreach (Field f in allFields) { 319 | f.BombDamage = new bool[4]; 320 | } 321 | foreach (Bomb b in allFields.SelectMany(f => f.Bombs)) { 322 | b.Tick(); 323 | } 324 | 325 | //give score for hit boxes, remove bombs stuff 326 | foreach (Field f in allFields) { 327 | for (int i = 0; i < f.BombDamage.Length; i++) { 328 | if (f.BombDamage[i] && f.Box) 329 | players[i].Score++; 330 | } 331 | if (f.BombDamage.Any(d => d)) { 332 | f.Bombs.Clear(); 333 | if (f.Box) 334 | f.Box = false; 335 | else 336 | f.PowerUp = null; 337 | foreach (Player p in players.Where(p => !p.Dead && p.Location == f)) { 338 | Console.Error.WriteLine("###Error " + p.ID + " Lost hit by bomb :("); 339 | p.Dead = true; 340 | } 341 | } 342 | } 343 | 344 | //apply player actions 345 | foreach (Player p in players.Where(p => !p.Dead)) { 346 | p.Score += (1 + MAX_BOXES); //for staying alive 347 | 348 | if (p.PlaceBomb) { 349 | p.Location.Bombs.Add(new Bomb(p.Location, p.BombRange, p)); 350 | p.BombFree--; 351 | } 352 | p.Location = p.NewLocation; 353 | if (p.Location.PowerUp != null) { 354 | if (p.Location.PowerUp.ExtraBomb) 355 | p.BombFree++; 356 | if (p.Location.PowerUp.ExtraRange) 357 | p.BombRange++; 358 | } 359 | } 360 | foreach (Player p in players) { 361 | p.Location.PowerUp = null; 362 | } 363 | 364 | bool earlyEnd = !allFields.Any(f => f.Box); 365 | if (earlyEnd && round + ROUNDS_AFTER_LAST_BOX < MAX_ROUNDS) 366 | round = MAX_ROUNDS - ROUNDS_AFTER_LAST_BOX; 367 | } 368 | 369 | private IEnumerable SymmetricFields(int x, int y) 370 | { 371 | if (x == WIDTH - 1 - x && y == HEIGHT - 1 - y || x + y < 2) 372 | yield break; //no box in center (already put before if odd number) and at player starting positions 373 | yield return Grid[x, y]; 374 | if (x < WIDTH - 1 - x) 375 | yield return Grid[WIDTH - 1 - x, y]; 376 | if (y < HEIGHT - 1 - y) 377 | yield return Grid[x, HEIGHT - 1 - y]; 378 | if (x < WIDTH - 1 - x && y < HEIGHT - 1 - y) 379 | yield return Grid[WIDTH - 1 - x, HEIGHT - 1 - y]; 380 | } 381 | 382 | public override string ToString() 383 | { 384 | StringBuilder sb = new StringBuilder(); 385 | for (int y = 0; y < HEIGHT; y++) { 386 | for (int x = 0; x < WIDTH; x++) { 387 | sb.Append(Grid[x, y]); 388 | } 389 | sb.AppendLine(); 390 | } 391 | List items = new List(); 392 | foreach (Player p in players.Where(p => !p.Dead)) 393 | items.Add(p.ToString()); 394 | foreach (Field f in allFields) { 395 | foreach (Bomb b in f.Bombs) 396 | items.Add(b.ToString()); 397 | if (!f.Box && f.PowerUp != null) 398 | items.Add(f.PowerUp.ToString()); 399 | } 400 | sb.AppendLine(items.Count.ToString()); 401 | foreach (string item in items) 402 | sb.AppendLine(item); 403 | return sb.ToString(); 404 | } 405 | } 406 | 407 | class Field 408 | { 409 | public int X { get; private set; } 410 | public int Y { get; private set; } 411 | public bool Wall { get; private set; } 412 | public List Bombs { get; private set; } 413 | public bool Box { get; set; } 414 | public PowerUp PowerUp { get; set; } 415 | public Field[] Neighbors { get; private set; } 416 | public bool[] BombDamage { get; set; } 417 | 418 | public Field(int x, int y) 419 | { 420 | this.X = x; 421 | this.Y = y; 422 | this.Wall = x % 2 == 1 && y % 2 == 1; 423 | this.Bombs = new List(); 424 | } 425 | 426 | public void InitNeighbors(Field[,] grid) 427 | { 428 | this.Neighbors = new Field[4]; 429 | for (int dir = 0; dir < 4; dir++) { 430 | int x = this.X + Referee.Offset[dir, 0]; 431 | int y = this.Y + Referee.Offset[dir, 1]; 432 | if (x >= 0 & x < Board.WIDTH && y >= 0 && y < Board.HEIGHT) 433 | Neighbors[dir] = grid[x, y]; 434 | } 435 | } 436 | 437 | public override string ToString() 438 | { 439 | if (Wall) 440 | return "X"; 441 | if (Box) { 442 | if (PowerUp == null) 443 | return "0"; 444 | if (PowerUp.ExtraRange) 445 | return "1"; 446 | return "2"; 447 | } 448 | return "."; 449 | } 450 | } 451 | 452 | class PowerUp 453 | { 454 | public bool ExtraRange { get; set; } 455 | public bool ExtraBomb { get; set; } 456 | public Field field; 457 | 458 | public PowerUp() 459 | { 460 | } 461 | 462 | public override string ToString() 463 | { 464 | return "2 0 " + field.X + " " + field.Y + " " + (ExtraRange ? "1" : "2") + " " + (ExtraRange ? "1" : "2"); 465 | } 466 | } 467 | 468 | class Bomb 469 | { 470 | public static readonly int INITIAL_TIMER = 8; 471 | 472 | public int Timer { get; private set; } 473 | public Field Location { get; private set; } 474 | public int Range { get; private set; } 475 | public Player Owner { get; private set; } 476 | 477 | public Bomb(Field field, int range, Player owner) 478 | { 479 | this.Timer = INITIAL_TIMER; 480 | this.Location = field; 481 | this.Range = range; 482 | this.Owner = owner; 483 | } 484 | 485 | public void Tick() 486 | { 487 | if (--Timer == 0) 488 | Explode(); 489 | } 490 | 491 | public void Explode() 492 | { 493 | Owner.BombFree++; 494 | Location.BombDamage[Owner.ID] = true; 495 | for (int dir = 0; dir < 4; dir++) { 496 | Field f = Location; 497 | for (int range = 1; range < this.Range; range++) { 498 | f = f.Neighbors[dir]; 499 | if (f == null) 500 | break; 501 | f.BombDamage[Owner.ID] = true; 502 | if (f.Wall || f.Box || f.PowerUp != null) 503 | break; 504 | if (f.Bombs.Count > 0) { 505 | foreach (Bomb b in f.Bombs) { 506 | if (b.Timer > 0) { 507 | b.Timer = 0; 508 | b.Explode(); 509 | } 510 | } 511 | break; 512 | } 513 | } 514 | } 515 | } 516 | 517 | public override string ToString() 518 | { 519 | return "1 " + Owner.ID + " " + Location.X + " " + Location.Y + " " + Timer + " " + Range; 520 | } 521 | } 522 | -------------------------------------------------------------------------------- /HyperSonic/img/Bomb1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Bomb1.png -------------------------------------------------------------------------------- /HyperSonic/img/Bomb2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Bomb2.png -------------------------------------------------------------------------------- /HyperSonic/img/Bomb3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Bomb3.png -------------------------------------------------------------------------------- /HyperSonic/img/Bomb4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Bomb4.png -------------------------------------------------------------------------------- /HyperSonic/img/Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Box.png -------------------------------------------------------------------------------- /HyperSonic/img/Player1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Player1.png -------------------------------------------------------------------------------- /HyperSonic/img/Player2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Player2.png -------------------------------------------------------------------------------- /HyperSonic/img/Player3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Player3.png -------------------------------------------------------------------------------- /HyperSonic/img/Player4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Player4.png -------------------------------------------------------------------------------- /HyperSonic/img/Wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/Wall.png -------------------------------------------------------------------------------- /HyperSonic/img/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/background.png -------------------------------------------------------------------------------- /HyperSonic/img/bombExtra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/bombExtra.png -------------------------------------------------------------------------------- /HyperSonic/img/bombRange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/HyperSonic/img/bombRange.png -------------------------------------------------------------------------------- /PokerChipRace/PokerChipRaceRefereeIncomplete.cs: -------------------------------------------------------------------------------- 1 | // this is not a complete referee on purpose, as the game is at least 95% about writing a working simulation 2 | // I do not guarantee that it is bugfree either, but it can't be off too far 3 | // for collisions see also: http://files.magusgeek.com/csb/csb_en.html 4 | 5 | private void Simulate() 6 | { 7 | double epsilon = 1e-9; 8 | foreach (Chip c in Chips.Where(c => c.MovementPlan != null).ToList()) 9 | { 10 | //CREATE NEW DROPS 11 | double alpha = Math.Atan2(c.MovementPlan.Y - c.Y, c.MovementPlan.X - c.X); 12 | double radius = c.Radius * Math.Sqrt(1.0 / 15); 13 | c.Radius *= Math.Sqrt(14.0 / 15); 14 | double dropX = c.X - (c.Radius - radius) * Math.Cos(alpha); 15 | double dropY = c.Y - (c.Radius - radius) * Math.Sin(alpha); 16 | double dropVx = c.VX - 200 * Math.Cos(alpha); 17 | double dropVy = c.VY - 200 * Math.Sin(alpha); 18 | c.VX += 200 * Math.Cos(alpha) / 14; 19 | c.VY += 200 * Math.Sin(alpha) / 14; 20 | 21 | Chip drop = new Chip(-1, dropX, dropY, dropVx, dropVy, radius); 22 | drop.Parent = c; 23 | Chips.Add(drop); 24 | } 25 | 26 | double time = 0; 27 | while (time < 1) 28 | { 29 | List collisions = new List(); 30 | for (int c1Index = 0; c1Index < Chips.Count; c1Index++) 31 | { 32 | Chip chip = Chips[c1Index]; 33 | for (int c2Index = c1Index + 1; c2Index < Chips.Count; c2Index++) 34 | { 35 | if (chip.Parent == Chips[c2Index].Parent) continue; 36 | Collision c = Collision.Collide(chip, Chips[c2Index]); 37 | if (c != null) collisions.Add(c); 38 | } 39 | Collision collideEdge = chip.CollideEdge(); 40 | collisions.Add(collideEdge); 41 | } 42 | collisions.Sort(); 43 | 44 | Collision collision = collisions.FirstOrDefault(); 45 | List newCollisions = new List(); 46 | double delta = 1 - time; 47 | if (collision != null && collision.Time < 0) 48 | collision.Time = 0; //already touching because of multi absorbtion 49 | if (collision != null) delta = Math.Min(delta, collision.Time); 50 | delta += epsilon; 51 | time += delta; 52 | foreach (Chip c in Chips) c.Move(delta); 53 | Chip c1 = collision?.C1; 54 | Chip c2 = collision?.C2; 55 | 56 | if (c2 != null && collision.Time <= delta) //real collision, not just edge 57 | { 58 | c2.Parent = c2; 59 | double m1 = c1.Radius * c1.Radius; 60 | double m2 = c2.Radius * c2.Radius; 61 | if (c1.Radius == c2.Radius) 62 | { 63 | double mcoeff = (m1 + m2) / (m1 * m2); 64 | double nx = c1.X - c2.X; 65 | double ny = c1.Y - c2.Y; 66 | double nxnysquare = nx * nx + ny * ny; 67 | double dvx = c1.VX - c2.VX; 68 | double dvy = c1.VY - c2.VY; 69 | double product = nx * dvx + ny * dvy; 70 | double fx = (nx * product) / (nxnysquare * mcoeff); 71 | double fy = (ny * product) / (nxnysquare * mcoeff); 72 | c1.VX -= fx / m1; 73 | c1.VY -= fy / m1; 74 | c2.VX += fx / m2; 75 | c2.VY += fy / m2; 76 | double impulse = Math.Sqrt(fx * fx + fy * fy); 77 | c1.VX -= fx / m1; 78 | c1.VY -= fy / m1; 79 | c2.VX += fx / m2; 80 | c2.VY += fy / m2; 81 | 82 | c1.Move(epsilon); 83 | c2.Move(epsilon); 84 | } 85 | else 86 | { 87 | double x = c1.X + (c2.X - c1.X) * m2 / (m1 + m2); 88 | double y = c1.Y + (c2.Y - c1.Y) * m2 / (m1 + m2); 89 | double vx = (c1.VX * m1 + c2.VX * m2) / (m1 + m2); 90 | double vy = (c1.VY * m1 + c2.VY * m2) / (m1 + m2); 91 | 92 | if (c1.Radius > c2.Radius) 93 | { 94 | c1.X = x; 95 | c1.Y = y; 96 | c1.VX = vx; 97 | c1.VY = vy; 98 | c1.Radius = Math.Sqrt(m1 + m2); 99 | c1.Move(epsilon); //get away from edge 100 | Chips.Remove(c2); 101 | } 102 | else 103 | { 104 | c2.X = x; 105 | c2.Y = y; 106 | c2.VX = vx; 107 | c2.VY = vy; 108 | c2.Radius = Math.Sqrt(m1 + m2); 109 | c2.Move(epsilon); //get away from edge 110 | Chips.Remove(c1); 111 | } 112 | } 113 | } 114 | } 115 | Chips.Sort((a, b) => a.ID.CompareTo(b.ID)); 116 | } 117 | 118 | class Chip 119 | { 120 | public int ID { get; private set; } 121 | public int Player; 122 | public double X { get; private set; } 123 | public double Y { get; private set; } 124 | public double VX; 125 | public double VY; 126 | public double Radius; 127 | public Point MovementPlan = null; 128 | public Chip Parent; 129 | private static int counter = 1; 130 | 131 | public Chip(int player, double x, double y, double vx, double vy, double radius) : this(player, counter++, x, y, vx, vy, radius) { } 132 | 133 | public Chip(int player, int id, double x, double y, double vx, double vy, double radius) 134 | { 135 | this.ID = id; 136 | this.Player = player; 137 | this.X = x; 138 | this.Y = y; 139 | this.VX = vx; 140 | this.VY = vy; 141 | this.Radius = radius; 142 | this.Parent = this; 143 | } 144 | 145 | public Collision CollideEdge() 146 | { 147 | double collideEdge = double.MaxValue; 148 | if (this.VX > 0) collideEdge = (Board.WIDTH - this.X - this.Radius) / this.VX; 149 | else if (this.VX < 0) collideEdge = -(this.X - this.Radius) / this.VX; 150 | if (this.VY > 0 && (Board.HEIGHT - this.Y - this.Radius) / this.VY < collideEdge) collideEdge = Math.Min(collideEdge, (Board.HEIGHT - this.Y - this.Radius) / this.VY); 151 | else if (this.VY < 0 && -(this.Y - this.Radius) / this.VY < collideEdge) collideEdge = Math.Min(collideEdge, -(this.Y - this.Radius) / this.VY); 152 | return new Collision(this, null, collideEdge); 153 | } 154 | 155 | public void Move(double time) 156 | { 157 | this.X += time * VX; 158 | this.Y += time * VY; 159 | if (X < Radius || X == Radius && time > 0) 160 | { 161 | X = Radius; 162 | VX *= -1; 163 | this.Parent = this; 164 | } 165 | if (X + Radius > Board.WIDTH || X + Radius == Board.WIDTH && time > 0) 166 | { 167 | X = Board.WIDTH - Radius; 168 | VX *= -1; 169 | this.Parent = this; 170 | } 171 | if (Y < Radius || Y == Radius && time > 0) 172 | { 173 | Y = Radius; 174 | VY *= -1; 175 | this.Parent = this; 176 | } 177 | if (Y + Radius > Board.HEIGHT || Y + Radius == Board.HEIGHT && time > 0) 178 | { 179 | Y = Board.HEIGHT - Radius; 180 | VY *= -1; 181 | this.Parent = this; 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /PokerChipRace/pcr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eulerscheZahl/RefereeCollection/9c31fb83f818c76a4fea7bcad5faabe4e8f3c7e2/PokerChipRace/pcr.gif -------------------------------------------------------------------------------- /PokerChipRace/readme.md: -------------------------------------------------------------------------------- 1 | #Poker Chip Race 2 | ![Animation](pcr.gif) 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Official referees 2 | After I wrote those referees, the real ones used by CodinGame were leaked [here](https://github.com/SpiritusSancti5/codinGame/tree/master/Referees). 3 | Those are the single source of truth if you want to understand how the game really works. 4 | 5 | # CodinGame Referee Collection 6 | This is an unofficial collection of referee programs for CodinGame multiplayer games, compatible to [brutaltester](https://github.com/dreignier/cg-brutaltester). 7 | The referees are not ported from the code used on the servers, so correctness can't be garanteed. This applied especially for, but is not limited to map generation. 8 | 9 | The referees support some basic graphic feedback. 10 | To activate it, pass a folder (or `.` for the current directory) as first command line argument and you will get an image for each turn. 11 | This is not recommended when playing multiple matches, as it is slow and images will be replaced by later runs. 12 | 13 | # Getting started 14 | The referees are written in C#. On Windows the sould run out of the box (Windows XP with service pack 3 or above). If not, check for updates of the .NET framework. 15 | On Linux install the mono package with `apt-get install mono` (Ubuntu) to execute the referees. 16 | 17 | # Not implemented 18 | ## HyperSonic 19 | MOVE doesn't find shortest paths. It works fine, as long as you always go to adjacent cells. 20 | When you use the referee to optimize you bot, you most likely use your own pathfinding anyway. 21 | -------------------------------------------------------------------------------- /SmashTheCode/SmashTheCode.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | {354EBC6A-CCD3-4574-96D7-4F9B24057DF8} 7 | Exe 8 | SmashTheCode 9 | SmashTheCode 10 | v4.5 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug 17 | DEBUG; 18 | prompt 19 | 4 20 | true 21 | x86 22 | 23 | 24 | full 25 | true 26 | bin\Release 27 | prompt 28 | 4 29 | true 30 | x86 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /SmashTheCode/SmashTheCode.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmashTheCode", "SmashTheCode.csproj", "{354EBC6A-CCD3-4574-96D7-4F9B24057DF8}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {354EBC6A-CCD3-4574-96D7-4F9B24057DF8}.Debug|x86.ActiveCfg = Debug|x86 13 | {354EBC6A-CCD3-4574-96D7-4F9B24057DF8}.Debug|x86.Build.0 = Debug|x86 14 | {354EBC6A-CCD3-4574-96D7-4F9B24057DF8}.Release|x86.ActiveCfg = Release|x86 15 | {354EBC6A-CCD3-4574-96D7-4F9B24057DF8}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /SmashTheCode/SmashTheCodeReferee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | 6 | public class SmashTheCodeReferee 7 | { 8 | static readonly int MAX_ROUNDS = 200; 9 | static readonly int PREVIEW = 8; 10 | public static void Main(string[] args) 11 | { 12 | string path = args.Length == 1 ? args[0] : null; 13 | Random random = new Random(); 14 | Stone[] allStones = new Stone[MAX_ROUNDS + PREVIEW]; 15 | for (int i = 0; i < allStones.Length; i++) 16 | { 17 | allStones[i] = new Stone(random); 18 | } 19 | 20 | //read ###Start 2, as there are 2 players 21 | Console.ReadLine(); 22 | 23 | Player p1 = new Player(0); 24 | Player p2 = new Player(1); 25 | for (int round = 0; round < MAX_ROUNDS; round++) 26 | { 27 | Stone[] visibleStones = Enumerable.Range(round, PREVIEW).Select(i => allStones[i]).ToArray(); 28 | if (path != null) 29 | { 30 | Bitmap bmp = new Bitmap((Board.WIDTH * 2 + 1) * 20, Board.HEIGHT * 20 + 80); 31 | using (Graphics g = Graphics.FromImage(bmp)) 32 | { 33 | g.Clear(Color.White); 34 | for (int i = 0; i < visibleStones.Length; i++) 35 | { 36 | using (Brush b = new SolidBrush(Stone.Colors[visibleStones[i].Color1])) 37 | g.FillEllipse(b, bmp.Width / 2 - 42 + 12 * i, 55, 10, 10); 38 | using (Brush b = new SolidBrush(Stone.Colors[visibleStones[i].Color2])) 39 | g.FillEllipse(b, bmp.Width / 2 - 42 + 12 * i, 65, 10, 10); 40 | } 41 | } 42 | p1.Draw(bmp); 43 | p2.Draw(bmp); 44 | bmp.Save(path + System.IO.Path.DirectorySeparatorChar + $"{round:000}.png"); 45 | bmp.Dispose(); 46 | } 47 | 48 | List p1Input = p1.GiveInput(p2, visibleStones); 49 | List p2Input = p2.GiveInput(p1, visibleStones); 50 | Console.WriteLine(string.Join("\n", p1Input)); 51 | int p1Skulls = p1.ReadAction(allStones[round]); 52 | bool p1Alive = p1Skulls >= 0; 53 | Console.WriteLine(string.Join("\n", p2Input)); 54 | int p2Skulls = p2.ReadAction(allStones[round]); 55 | bool p2Alive = p2Skulls >= 0; 56 | p1.AddSkulls(p2Skulls); 57 | p2.AddSkulls(p1Skulls); 58 | if (!p1Alive || !p2Alive) break; 59 | } 60 | //win by score 61 | if (p1.Score > p2.Score) 62 | Console.WriteLine("###End 0 1"); 63 | else if (p1.Score < p2.Score) 64 | Console.WriteLine("###End 1 0"); 65 | else 66 | Console.WriteLine("###End 01"); 67 | } 68 | 69 | public class Player 70 | { 71 | public int ID { get; private set; } 72 | public int Score { get; private set; } 73 | private Board board = new Board(); 74 | 75 | public Player(int id) 76 | { 77 | this.ID = id; 78 | } 79 | 80 | public void Draw(Bitmap bmp) 81 | { 82 | board.Draw(bmp, this); 83 | } 84 | 85 | public List GiveInput(Player opponent, Stone[] stones) 86 | { 87 | List result = new List(); 88 | result.Add("###Input " + ID); 89 | foreach (Stone s in stones) 90 | { 91 | result.Add(s.Color1 + " " + s.Color2); 92 | } 93 | result.Add(this.Score.ToString()); 94 | result.AddRange(this.board.Print()); 95 | result.Add(opponent.Score.ToString()); 96 | result.AddRange(opponent.board.Print()); 97 | return result; 98 | } 99 | 100 | public void AddSkulls(int rows) 101 | { 102 | this.board.AddSkulls(rows); 103 | } 104 | 105 | /// 106 | /// read action from player and apply it 107 | /// 108 | /// the stone to place next 109 | /// the number of skull rows or -1 for an invalid action 110 | public int ReadAction(Stone stone) 111 | { 112 | Console.WriteLine("###Output " + ID + " 1"); 113 | string line = Console.ReadLine(); 114 | try 115 | { 116 | string[] parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToArray(); 117 | int x = int.Parse(parts[0]); 118 | int rot = int.Parse(parts[1]); 119 | if (x < 0 || x >= Board.WIDTH || rot < 0 || rot > 3) 120 | return -1; //out of bounds 121 | int roundScore = board.PlaceStone(stone, x, rot); 122 | if (roundScore < 0) 123 | { 124 | this.Score = -1; 125 | return -1; 126 | } 127 | int oldSkullRows = Score / (Board.WIDTH * Board.SKULL_COST); 128 | Score += roundScore; 129 | int newSkullRows = Score / (Board.WIDTH * Board.SKULL_COST); 130 | return newSkullRows - oldSkullRows; 131 | } 132 | catch (Exception) 133 | { //invalid format 134 | this.Score = -1; 135 | return -1; 136 | } 137 | } 138 | } 139 | 140 | public class Board 141 | { 142 | public static readonly int WIDTH = 6; 143 | public static readonly int HEIGHT = 12; 144 | public static readonly int SKULL_COST = 70; 145 | private static readonly int FREE = -1; 146 | private static readonly int SKULL = 0; 147 | private static readonly int GROUP_MIN_SIZE = 4; 148 | 149 | private int[,] grid = new int[WIDTH, HEIGHT]; 150 | 151 | public Board() 152 | { 153 | for (int x = 0; x < WIDTH; x++) 154 | { 155 | for (int y = 0; y < HEIGHT; y++) 156 | { 157 | grid[x, y] = FREE; 158 | } 159 | } 160 | } 161 | 162 | public void Draw(Bitmap bmp, Player p) 163 | { 164 | using (Graphics g = Graphics.FromImage(bmp)) 165 | { 166 | for (int x = 0; x < WIDTH; x++) 167 | { 168 | for (int y = 0; y < HEIGHT; y++) 169 | { 170 | if (grid[x, y] == FREE) break; 171 | using (Brush b = new SolidBrush(Stone.Colors[grid[x, y]])) 172 | g.FillEllipse(b, 20 * (x + 7 * p.ID), bmp.Height - 20 * (1 + y), 20, 20); 173 | } 174 | } 175 | g.DrawString(p.Score.ToString(), new Font(new FontFamily("Arial"), 30), Brushes.Black, 5 + 140 * p.ID, 5); 176 | } 177 | } 178 | 179 | /// 180 | /// place a stone in the board 181 | /// 182 | /// the stone 183 | /// the location 184 | /// the rotation 185 | /// the score for placing the stone or -1 if the move is invalid 186 | public int PlaceStone(Stone stone, int x, int rotation) 187 | { 188 | if (grid[x, HEIGHT - 1] != FREE || 189 | rotation % 2 == 1 && grid[x, HEIGHT - 2] != FREE || 190 | rotation == 0 && (x == WIDTH - 1 || grid[x + 1, HEIGHT - 1] != FREE) || 191 | rotation == 2 && (x == 0 || grid[x - 1, HEIGHT - 1] != FREE)) 192 | return -1; 193 | 194 | //place stone 195 | switch (rotation) 196 | { 197 | case 0: 198 | grid[x, HEIGHT - 1] = stone.Color1; 199 | grid[x + 1, HEIGHT - 1] = stone.Color2; 200 | break; 201 | case 1: 202 | grid[x, HEIGHT - 2] = stone.Color1; 203 | grid[x, HEIGHT - 1] = stone.Color2; 204 | break; 205 | case 2: 206 | grid[x, HEIGHT - 1] = stone.Color1; 207 | grid[x - 1, HEIGHT - 1] = stone.Color2; 208 | break; 209 | case 3: 210 | grid[x, HEIGHT - 1] = stone.Color1; 211 | grid[x, HEIGHT - 2] = stone.Color2; 212 | break; 213 | } 214 | return Eval(grid); 215 | } 216 | 217 | public void AddSkulls(int rows) 218 | { 219 | for (int x = 0; x < WIDTH; x++) 220 | { 221 | int y = 0; 222 | while (y + 1 < HEIGHT && grid[x, y] != FREE) 223 | y++; 224 | for (int r = 0; r < rows && r + y < HEIGHT; r++) 225 | grid[x, r + y] = SKULL; 226 | } 227 | } 228 | 229 | private static readonly int[] cb = new int[] { 0, 0, 2, 4, 8, 16 }; 230 | private static int CB(bool[] colors) 231 | { 232 | return cb[colors.Count(c => c)]; 233 | } 234 | 235 | private static readonly int[] gb = new int[] { 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6 }; 236 | private static int GB(int n) 237 | { 238 | if (n >= gb.Length) 239 | return 8; 240 | return gb[n]; 241 | } 242 | 243 | private static int Eval(int[,] grid) 244 | { 245 | int result = 0; 246 | int chain = 0; 247 | while (true) 248 | { 249 | BlockFalling(grid); 250 | int removedStones = 0; 251 | int score = BlockRemove(grid, out removedStones) + chain; 252 | if (removedStones == 0) 253 | break; 254 | if (score == 0) 255 | score = 1; 256 | result += 10 * removedStones * score; 257 | if (chain == 0) 258 | chain = 4; 259 | chain *= 2; 260 | } 261 | return result; 262 | } 263 | 264 | private static readonly int[,] offset = new int[,] { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } }; 265 | private static int BlockRemove(int[,] grid, out int stonesRemoved) 266 | { 267 | List> blocks = new List>(); 268 | bool[,] visited = new bool[WIDTH, HEIGHT]; 269 | //find groups 270 | for (int x = 0; x < WIDTH; x++) 271 | { 272 | for (int y = 0; y < HEIGHT; y++) 273 | { 274 | if (visited[x, y] || grid[x, y] == FREE || grid[x, y] == SKULL) 275 | continue; 276 | Queue active = new Queue(); 277 | active.Enqueue(new Point(x, y)); 278 | List found = new List(); 279 | while (active.Count > 0) 280 | { 281 | Point p = active.Dequeue(); 282 | if (visited[p.X, p.Y]) 283 | continue; 284 | visited[p.X, p.Y] = true; 285 | found.Add(p); 286 | for (int dir = 0; dir < 4; dir++) 287 | { 288 | Point q = new Point(p.X + offset[dir, 0], p.Y + offset[dir, 1]); 289 | if (q.X >= 0 && q.Y >= 0 && q.X < WIDTH && q.Y < HEIGHT && grid[p.X, p.Y] == grid[q.X, q.Y]) 290 | active.Enqueue(q); 291 | } 292 | } 293 | if (found.Count >= GROUP_MIN_SIZE) 294 | blocks.Add(found); 295 | } 296 | } 297 | 298 | //remove groups 299 | bool[] colorsUsed = new bool[cb.Length]; 300 | foreach (List block in blocks) 301 | { 302 | foreach (Point p in block) 303 | { 304 | colorsUsed[grid[p.X, p.Y]] = true; 305 | grid[p.X, p.Y] = FREE; 306 | for (int dir = 0; dir < 4; dir++) 307 | { 308 | Point q = new Point(p.X + offset[dir, 0], p.Y + offset[dir, 1]); 309 | if (q.X >= 0 && q.Y >= 0 && q.X < WIDTH && q.Y < HEIGHT && grid[q.X, q.Y] == SKULL) 310 | grid[q.X, q.Y] = FREE; 311 | } 312 | } 313 | } 314 | 315 | //calculate score 316 | stonesRemoved = blocks.Sum(block => block.Count); 317 | return CB(colorsUsed) + blocks.Sum(block => GB(block.Count)); 318 | } 319 | 320 | private static void BlockFalling(int[,] grid) 321 | { 322 | for (int x = 0; x < WIDTH; x++) 323 | { 324 | for (int y = 1; y < HEIGHT; y++) 325 | { 326 | if (grid[x, y - 1] == FREE && grid[x, y] != FREE) 327 | { 328 | int destY = y - 1; 329 | while (destY > 0 && grid[x, destY - 1] == FREE) 330 | { 331 | destY--; 332 | } 333 | grid[x, destY] = grid[x, y]; 334 | grid[x, y] = FREE; 335 | } 336 | } 337 | } 338 | } 339 | 340 | public List Print() 341 | { 342 | string[] lines = new string[HEIGHT]; 343 | for (int y = 0; y < HEIGHT; y++) 344 | { 345 | string line = ""; 346 | for (int x = 0; x < WIDTH; x++) 347 | { 348 | line += grid[x, y] == FREE ? "." : grid[x, y].ToString(); 349 | } 350 | lines[HEIGHT - 1 - y] = line; 351 | } 352 | return lines.ToList(); 353 | } 354 | 355 | } 356 | 357 | public class Stone 358 | { 359 | public static Color[] Colors = new Color[] { Color.Gray, Color.Red, Color.Green, Color.Blue, Color.Yellow, Color.Purple }; 360 | public int Color1 { get; private set; } 361 | public int Color2 { get; private set; } 362 | private static readonly int COLOR_COUNT = 5; 363 | 364 | public Stone(Random random) 365 | { 366 | Color1 = random.Next(COLOR_COUNT) + 1; 367 | Color2 = random.Next(COLOR_COUNT) + 1; 368 | } 369 | } 370 | } -------------------------------------------------------------------------------- /TheGreatEscape/TheGreatEscape.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | {91E98F1F-E077-41D6-B16D-1E4C1B3E1D4F} 7 | Exe 8 | TheGreatEscape 9 | TheGreatEscape 10 | v4.5 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug 17 | DEBUG; 18 | prompt 19 | 4 20 | true 21 | x86 22 | 23 | 24 | full 25 | true 26 | bin\Release 27 | prompt 28 | 4 29 | true 30 | x86 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /TheGreatEscape/TheGreatEscape.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheGreatEscape", "TheGreatEscape.csproj", "{91E98F1F-E077-41D6-B16D-1E4C1B3E1D4F}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {91E98F1F-E077-41D6-B16D-1E4C1B3E1D4F}.Debug|x86.ActiveCfg = Debug|x86 13 | {91E98F1F-E077-41D6-B16D-1E4C1B3E1D4F}.Debug|x86.Build.0 = Debug|x86 14 | {91E98F1F-E077-41D6-B16D-1E4C1B3E1D4F}.Release|x86.ActiveCfg = Release|x86 15 | {91E98F1F-E077-41D6-B16D-1E4C1B3E1D4F}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /TheGreatEscape/TheGreatEscapeReferee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | 6 | class TheGreatEscapeReferee 7 | { 8 | public static void Main(string[] args) 9 | { 10 | string path = args.Length == 1 ? args [0] : null; 11 | 12 | int seed = -1; 13 | while (true) { 14 | string[] lineParts = Console.ReadLine ().Split (); 15 | if (lineParts [0] == "###Seed") 16 | seed = int.Parse (lineParts [1]); 17 | else if (lineParts [0] == "###Start") { 18 | int playerCount = int.Parse (lineParts [1]); 19 | Board board = new Board (playerCount, seed); 20 | if (path != null) { 21 | Bitmap bmp = board.Draw (); 22 | bmp.Save (path + System.IO.Path.DirectorySeparatorChar + "000.png"); 23 | bmp.Dispose (); 24 | } 25 | 26 | while (board.Play ()) { 27 | board.Tick (path); 28 | } 29 | board.DeclareWinner (); 30 | } 31 | } 32 | } 33 | 34 | class Board 35 | { 36 | public static readonly int SIZE = 9; 37 | public static readonly int MAX_ROUNDS = 100; 38 | 39 | private static Random random = new Random(); 40 | private List activePlayers = new List(); 41 | private List finishedPlayers = new List(); 42 | private int playerCount; 43 | public int Round { get; private set; } 44 | 45 | private Field[,] Grid; 46 | private bool[,,] Walls; 47 | private List wallList = new List(); 48 | private static int hor = 0; 49 | private static int ver = 1; 50 | private static int[,] offset = new int[,] { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; 51 | private static string[] directions = new string[] { "DOWN", "RIGHT", "UP", "LEFT" }; 52 | 53 | public Board(int playerCount, int seed) 54 | { 55 | if (seed >= 0) random = new Random(seed); 56 | this.playerCount = playerCount; 57 | for (int i = 0; i < playerCount; i++) 58 | { 59 | activePlayers.Add(new Player(i, random, playerCount)); 60 | } 61 | 62 | this.Walls = new bool[SIZE + 1, SIZE + 1, 2]; 63 | Grid = new Field[SIZE, SIZE]; 64 | for (int x = 0; x < SIZE; x++) 65 | { 66 | for (int y = 0; y < SIZE; y++) 67 | { 68 | Grid[x, y] = new Field(x, y); 69 | } 70 | } 71 | for (int x = 0; x < SIZE; x++) 72 | { 73 | for (int y = 0; y < SIZE; y++) 74 | { 75 | for (int dir = 0; dir < 4; dir++) 76 | { 77 | int x_ = x + offset[dir, 0]; 78 | int y_ = y + offset[dir, 1]; 79 | if (x_ >= 0 && x_ < SIZE && y_ >= 0 && y_ < SIZE) 80 | Grid[x, y].Neighbors.Add(Grid[x_, y_]); 81 | } 82 | } 83 | } 84 | } 85 | 86 | public bool AddWall(Wall w) 87 | { 88 | if (Walls[w.X, w.Y, w.Horizontal ? hor : ver]) 89 | return false; 90 | if (w.Horizontal) 91 | { 92 | if (w.X < 0 || w.X >= 8 || w.Y <= 0 || w.Y > 8) //out of bounds 93 | return false; 94 | if (w.X > 0 && Walls[w.X - 1, w.Y, hor] || Walls[w.X + 1, w.Y, hor]) //blocked in same direction 95 | return false; 96 | if (w.Y > 0 && Walls[w.X + 1, w.Y - 1, ver]) //cross 97 | return false; 98 | } 99 | else 100 | { 101 | if (w.X <= 0 || w.X > 8 || w.Y < 0 || w.Y >= 8) //out of bounds 102 | return false; 103 | if (w.Y > 0 && Walls[w.X, w.Y - 1, ver] || Walls[w.X, w.Y + 1, ver]) //blocked in same direction 104 | return false; 105 | if (w.X > 0 && Walls[w.X - 1, w.Y + 1, hor]) //cross 106 | return false; 107 | } 108 | Walls[w.X, w.Y, w.Horizontal ? hor : ver] = true; 109 | if (w.Horizontal) 110 | { 111 | Field topLeft = Grid[w.X, w.Y - 1]; 112 | Field topRight = Grid[w.X + 1, w.Y - 1]; 113 | Field bottomLeft = Grid[w.X, w.Y]; 114 | Field bottomRight = Grid[w.X + 1, w.Y]; 115 | topLeft.Neighbors.Remove(bottomLeft); 116 | bottomLeft.Neighbors.Remove(topLeft); 117 | topRight.Neighbors.Remove(bottomRight); 118 | bottomRight.Neighbors.Remove(topRight); 119 | } 120 | else 121 | { 122 | Field topLeft = Grid[w.X - 1, w.Y]; 123 | Field topRight = Grid[w.X, w.Y]; 124 | Field bottomLeft = Grid[w.X - 1, w.Y + 1]; 125 | Field bottomRight = Grid[w.X, w.Y + 1]; 126 | topLeft.Neighbors.Remove(topRight); 127 | topRight.Neighbors.Remove(topLeft); 128 | bottomLeft.Neighbors.Remove(bottomRight); 129 | bottomRight.Neighbors.Remove(bottomLeft); 130 | } 131 | if (activePlayers.Any(p => !CanReachTarget(p))) 132 | { 133 | RemoveWall(w); 134 | return false; 135 | } 136 | wallList.Add(w); 137 | return true; 138 | } 139 | 140 | private bool CanReachTarget(Player p) 141 | { 142 | bool[,] visited = new bool[SIZE, SIZE]; 143 | visited[p.X, p.Y] = true; 144 | Queue front = new Queue(); 145 | front.Enqueue(Grid[p.X, p.Y]); 146 | while (front.Count > 0) 147 | { 148 | Field f = front.Dequeue(); 149 | foreach (Field f2 in f.Neighbors) 150 | { 151 | if (!visited[f2.X, f2.Y]) 152 | { 153 | visited[f2.X, f2.Y] = true; 154 | if (p.ID == 0 && f2.X == SIZE - 1 || p.ID == 1 && f2.X == 0 || p.ID == 2 && f2.Y == SIZE - 1) 155 | { 156 | return true; 157 | } 158 | front.Enqueue(f2); 159 | } 160 | } 161 | } 162 | return false; 163 | } 164 | 165 | public void RemoveWall(Wall w) 166 | { 167 | Walls[w.X, w.Y, w.Horizontal ? hor : ver] = false; 168 | if (w.Horizontal) 169 | { 170 | Field topLeft = Grid[w.X, w.Y - 1]; 171 | Field topRight = Grid[w.X + 1, w.Y - 1]; 172 | Field bottomLeft = Grid[w.X, w.Y]; 173 | Field bottomRight = Grid[w.X + 1, w.Y]; 174 | topLeft.Neighbors.Add(bottomLeft); 175 | bottomLeft.Neighbors.Add(topLeft); 176 | topRight.Neighbors.Add(bottomRight); 177 | bottomRight.Neighbors.Add(topRight); 178 | } 179 | else 180 | { 181 | Field topLeft = Grid[w.X - 1, w.Y]; 182 | Field topRight = Grid[w.X, w.Y]; 183 | Field bottomLeft = Grid[w.X - 1, w.Y + 1]; 184 | Field bottomRight = Grid[w.X, w.Y + 1]; 185 | topLeft.Neighbors.Add(topRight); 186 | topRight.Neighbors.Add(topLeft); 187 | bottomLeft.Neighbors.Add(bottomRight); 188 | bottomRight.Neighbors.Add(bottomLeft); 189 | } 190 | } 191 | 192 | public void Tick(string path) 193 | { 194 | foreach (Player p in activePlayers.ToList()) 195 | { 196 | Console.WriteLine("###Input " + p.ID); 197 | if (Round == 1) 198 | { 199 | Console.WriteLine($"{SIZE} {SIZE} {playerCount} {p.ID}"); 200 | } 201 | for (int i = 0; i < playerCount; i++) 202 | { 203 | Player toPrint = activePlayers.FirstOrDefault(pl => pl.ID == i); 204 | if (toPrint == null) Console.WriteLine("-1 -1 -1"); 205 | else Console.WriteLine(toPrint); 206 | } 207 | Console.WriteLine(wallList.Count); 208 | foreach (Wall w in wallList) Console.WriteLine(w); 209 | Console.WriteLine("###Output " + p.ID + " 1"); 210 | 211 | string[] action = Console.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); 212 | if (directions.Contains(action[0].ToUpper())) //movement 213 | { 214 | int index = directions.ToList().IndexOf(action[0].ToUpper()); 215 | int x = p.X + offset[index, 0]; 216 | int y = p.Y + offset[index, 1]; 217 | if (Grid[p.X, p.Y].Neighbors.Any(n => n.X == x && n.Y == y)) 218 | { 219 | p.X = x; 220 | p.Y = y; 221 | if (p.ID == 0 && p.X == SIZE - 1 || p.ID == 1 && p.X == 0 || p.ID == 2 && p.Y == SIZE - 1) 222 | { 223 | activePlayers.Remove(p); 224 | finishedPlayers.Add(p); 225 | } 226 | } 227 | else 228 | { 229 | activePlayers.Remove(p); 230 | Console.Error.WriteLine($"Player {p.ID}: illegal movement"); 231 | } 232 | } 233 | else 234 | { 235 | try 236 | { 237 | int x = int.Parse(action[0]); 238 | int y = int.Parse(action[1]); 239 | bool hor = action[2].ToUpper() == "H"; 240 | Wall wall = new Wall(x, y, hor, p.ID); 241 | p.RemainingWalls--; 242 | 243 | if (!"HV".Contains(action[2].ToUpper()) || p.RemainingWalls < 0 || !AddWall(wall)) 244 | { 245 | activePlayers.Remove(p); 246 | Console.Error.WriteLine($"Player {p.ID}: invalid wall placement"); 247 | continue; 248 | } 249 | } 250 | catch 251 | { 252 | activePlayers.Remove(p); 253 | Console.Error.WriteLine($"Player {p.ID}: invalid input"); 254 | } 255 | } 256 | 257 | 258 | if (path != null) 259 | { 260 | Bitmap bmp = Draw(); 261 | bmp.Save(path + System.IO.Path.DirectorySeparatorChar + $"{++frame:000}.png"); 262 | bmp.Dispose(); 263 | } 264 | } 265 | } 266 | 267 | private int frame = 0; 268 | public Bitmap Draw() 269 | { 270 | Color[] colors = new Color[] { Color.Orange, Color.Red, Color.Blue }; 271 | int scale = 50; 272 | Bitmap bmp = new Bitmap(SIZE * scale, SIZE * scale); 273 | using (Graphics g = Graphics.FromImage(bmp)) 274 | { 275 | g.Clear(Color.White); 276 | for (int i = 1; i < SIZE; i++) 277 | { 278 | g.DrawLine(Pens.Black, 0, i * scale, SIZE * scale, i * scale); 279 | g.DrawLine(Pens.Black, i * scale, 0, i * scale, SIZE * scale); 280 | } 281 | foreach (Player p in activePlayers) 282 | { 283 | g.FillEllipse(new SolidBrush(colors[p.ID]), p.X * scale, p.Y * scale, scale, scale); 284 | } 285 | foreach (Wall w in wallList) 286 | { 287 | if (w.Horizontal) g.FillRectangle(new SolidBrush(colors[w.Owner]), w.X * scale, w.Y * scale - 5, 2 * scale, 10); 288 | else g.FillRectangle(new SolidBrush(colors[w.Owner]), w.X * scale - 5, w.Y * scale, 10, 2 * scale); 289 | } 290 | } 291 | return bmp; 292 | } 293 | 294 | public bool Play() 295 | { 296 | return Round++ < MAX_ROUNDS && activePlayers.Count > 1; 297 | } 298 | 299 | public void DeclareWinner() 300 | { 301 | string result = "###End "; 302 | //winners 303 | if (finishedPlayers.Count > 0) result += string.Join(" ", finishedPlayers.Select(f => f.ID)) + " "; 304 | //moving players 305 | if (activePlayers.Count > 0) result += string.Concat(activePlayers.Select(f => f.ID)) + " "; 306 | //crashed players 307 | result += string.Concat(Enumerable.Range(0, playerCount).Where(i => !finishedPlayers.Union(activePlayers).Any(f => f.ID == i)).Select(i => i.ToString())); 308 | 309 | Console.WriteLine(result.Trim()); 310 | } 311 | } 312 | 313 | class Wall 314 | { 315 | public int X { get; private set; } 316 | public int Y { get; private set; } 317 | public bool Horizontal { get; private set; } 318 | public int Owner { get; private set; } 319 | 320 | public Wall(int x, int y, bool horizontal, int owner) 321 | { 322 | this.X = x; 323 | this.Y = y; 324 | this.Horizontal = horizontal; 325 | this.Owner = owner; 326 | } 327 | 328 | public override string ToString() 329 | { 330 | string orientation = Horizontal ? "H" : "V"; 331 | return $"{X} {Y} {orientation}"; 332 | } 333 | } 334 | 335 | class Field 336 | { 337 | public int X { get; private set; } 338 | public int Y { get; private set; } 339 | public HashSet Neighbors { get; private set; } 340 | 341 | public Field(int x, int y) 342 | { 343 | this.X = x; 344 | this.Y = y; 345 | Neighbors = new HashSet(); 346 | } 347 | 348 | public override string ToString() 349 | { 350 | return $"[Field: X={X}, Y={Y}, Neighbors={Neighbors.Count}]"; 351 | } 352 | } 353 | 354 | class Player 355 | { 356 | public int ID { get; private set; } 357 | public int X { get; set; } 358 | public int Y { get; set; } 359 | public int RemainingWalls { get; set; } 360 | 361 | public Player(int id, Random random, int playerCount) 362 | { 363 | this.ID = id; 364 | switch (id) 365 | { 366 | case 0: X = 0; Y = random.Next(Board.SIZE); break; 367 | case 1: X = Board.SIZE - 1; Y = random.Next(Board.SIZE); break; 368 | case 2: X = random.Next(Board.SIZE); Y = 0; break; 369 | } 370 | this.RemainingWalls = playerCount == 2 ? 10 : 6; 371 | } 372 | 373 | public override string ToString() 374 | { 375 | return $"{X} {Y} {RemainingWalls}"; 376 | } 377 | } 378 | } -------------------------------------------------------------------------------- /Tron/Tron.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | x86 6 | {5282C2BB-7D46-4886-91B1-BE592A30BBD3} 7 | Exe 8 | Tron 9 | Tron 10 | v4.5 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug 17 | DEBUG; 18 | prompt 19 | 4 20 | true 21 | x86 22 | 23 | 24 | full 25 | true 26 | bin\Release 27 | prompt 28 | 4 29 | true 30 | x86 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Tron/Tron.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tron", "Tron.csproj", "{5282C2BB-7D46-4886-91B1-BE592A30BBD3}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x86 = Debug|x86 9 | Release|x86 = Release|x86 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {5282C2BB-7D46-4886-91B1-BE592A30BBD3}.Debug|x86.ActiveCfg = Debug|x86 13 | {5282C2BB-7D46-4886-91B1-BE592A30BBD3}.Debug|x86.Build.0 = Debug|x86 14 | {5282C2BB-7D46-4886-91B1-BE592A30BBD3}.Release|x86.ActiveCfg = Release|x86 15 | {5282C2BB-7D46-4886-91B1-BE592A30BBD3}.Release|x86.Build.0 = Release|x86 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /Tron/TronReferee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | 6 | class TronReferee 7 | { 8 | public static void Main(string[] args) 9 | { 10 | string path = args.Length == 1 ? args[0] : null; 11 | 12 | int seed = -1; 13 | while (true) { 14 | string[] lineParts = Console.ReadLine ().Split (); 15 | if (lineParts [0] == "###Seed") 16 | seed = int.Parse (lineParts [1]); 17 | else if (lineParts [0] == "###Start") { 18 | int playerCount = int.Parse (lineParts [1]); 19 | Board board = new Board (playerCount, seed); 20 | if (path != null) { 21 | Bitmap bmp = board.Draw (); 22 | bmp.Save (path + System.IO.Path.DirectorySeparatorChar + "000.png"); 23 | bmp.Dispose (); 24 | } 25 | 26 | while (board.Play ()) { 27 | board.Tick (path); 28 | } 29 | board.DeclareWinner (); 30 | } 31 | } 32 | } 33 | 34 | class Board 35 | { 36 | public static readonly int WIDTH = 30; 37 | public static readonly int HEIGHT = 20; 38 | 39 | private static Random random = new Random(); 40 | private List activePlayers = new List(); 41 | private List deadPlayers = new List(); 42 | private int playerCount; 43 | public int[,] Grid = new int[WIDTH, HEIGHT]; 44 | 45 | public Board(int playerCount, int seed) 46 | { 47 | if (seed >= 0) random = new Random(seed); 48 | this.playerCount = playerCount; 49 | for (int i = 0; i < playerCount; i++) 50 | { 51 | activePlayers.Add(new Player(i, random, this)); 52 | } 53 | } 54 | 55 | private int round = 0; 56 | public void Tick(string path) 57 | { 58 | foreach (Player p in activePlayers.ToList()) { 59 | Console.WriteLine ("###Input " + p.ID); 60 | Console.WriteLine ($"{playerCount} {p.ID}"); 61 | for (int i = 0; i < playerCount; i++) { 62 | Player toPrint = activePlayers.FirstOrDefault (pl => pl.ID == i); 63 | if (toPrint == null) 64 | Console.WriteLine ("-1 -1 -1 -1"); 65 | else 66 | Console.WriteLine (toPrint); 67 | } 68 | Console.WriteLine ("###Output " + p.ID + " 1"); 69 | 70 | string action = Console.ReadLine ().Split (" ".ToCharArray (), StringSplitOptions.RemoveEmptyEntries) [0]; 71 | if (!p.Move (action, this)) { 72 | activePlayers.Remove (p); 73 | deadPlayers.Add (p); 74 | for (int x = 0; x < WIDTH; x++) { 75 | for (int y = 0; y < HEIGHT; y++) { 76 | if (Grid [x, y] == p.ID + 1) 77 | Grid [x, y] = 0; 78 | } 79 | } 80 | } 81 | 82 | if (path != null) { 83 | Bitmap bmp = Draw (); 84 | bmp.Save (path + System.IO.Path.DirectorySeparatorChar +$"{++frame:000}.png"); 85 | bmp.Dispose (); 86 | } 87 | } 88 | round++; 89 | } 90 | 91 | private int frame = 0; 92 | public Bitmap Draw() 93 | { 94 | Color[] colors = new Color[] { 95 | Color.Gray, 96 | Color.Orange, 97 | Color.Red, 98 | Color.Blue, 99 | Color.Violet 100 | }; 101 | int scale = 30; 102 | Bitmap bmp = new Bitmap (WIDTH * scale, HEIGHT * scale); 103 | using (Graphics g = Graphics.FromImage (bmp)) { 104 | g.Clear (Color.Black); 105 | for (int x = 0; x < WIDTH; x++) { 106 | for (int y = 0; y < HEIGHT; y++) { 107 | g.FillRectangle (new SolidBrush (colors [Grid [x, y]]), x * scale + 1, y * scale + 1, scale - 2, scale - 2); 108 | } 109 | } 110 | } 111 | return bmp; 112 | } 113 | 114 | public bool Play() 115 | { 116 | return activePlayers.Count > 1; 117 | } 118 | 119 | public void DeclareWinner() 120 | { 121 | deadPlayers.AddRange (activePlayers); 122 | deadPlayers.Reverse (); 123 | Console.WriteLine ("###End " + string.Join (" ", deadPlayers.Select (d => d.ID))); 124 | } 125 | } 126 | 127 | class Player 128 | { 129 | public int ID { get; private set; } 130 | public int X { get; set; } 131 | public int Y { get; set; } 132 | public int PrevX { get; set; } 133 | public int PrevY { get; set; } 134 | 135 | public Player(int id, Random random, Board board) 136 | { 137 | this.ID = id; 138 | int x = -1, y = -1; 139 | do 140 | { 141 | x = random.Next(Board.WIDTH); 142 | y = random.Next(Board.HEIGHT); 143 | } while (board.Grid[x, y] != 0); 144 | board.Grid[x, y] = id + 1; 145 | this.X = x; 146 | this.Y = y; 147 | this.PrevX = x; 148 | this.PrevY = y; 149 | } 150 | 151 | private static int[,] offset = new int[,] { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; 152 | private static string[] directions = new string[] { "DOWN", "RIGHT", "UP", "LEFT" }; 153 | public bool Move(string dir, Board board) 154 | { 155 | int index = directions.ToList ().IndexOf (dir.ToUpper ()); 156 | if (index == -1) 157 | return false; 158 | int x = this.X + offset [index, 0]; 159 | int y = this.Y + offset [index, 1]; 160 | if (x < 0 || x >= Board.WIDTH || y < 0 || y >= Board.HEIGHT || board.Grid [x, y] != 0) 161 | return false; 162 | board.Grid [x, y] = ID + 1; 163 | PrevX = this.X; 164 | this.X = x; 165 | PrevY = this.Y; 166 | this.Y = y; 167 | return true; 168 | } 169 | 170 | public override string ToString() 171 | { 172 | return $"{PrevX} {PrevY} {X} {Y}"; 173 | } 174 | } 175 | } --------------------------------------------------------------------------------