├── 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 | 
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 | }
--------------------------------------------------------------------------------