kaggle-environments 0.2.1__py3-none-any.whl → 1.20.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kaggle-environments might be problematic. Click here for more details.
- kaggle_environments/__init__.py +49 -13
- kaggle_environments/agent.py +177 -124
- kaggle_environments/api.py +31 -0
- kaggle_environments/core.py +295 -170
- kaggle_environments/envs/cabt/cabt.js +164 -0
- kaggle_environments/envs/cabt/cabt.json +28 -0
- kaggle_environments/envs/cabt/cabt.py +186 -0
- kaggle_environments/envs/cabt/cg/__init__.py +0 -0
- kaggle_environments/envs/cabt/cg/cg.dll +0 -0
- kaggle_environments/envs/cabt/cg/game.py +75 -0
- kaggle_environments/envs/cabt/cg/libcg.so +0 -0
- kaggle_environments/envs/cabt/cg/sim.py +48 -0
- kaggle_environments/envs/cabt/test_cabt.py +120 -0
- kaggle_environments/envs/chess/chess.js +4289 -0
- kaggle_environments/envs/chess/chess.json +60 -0
- kaggle_environments/envs/chess/chess.py +4241 -0
- kaggle_environments/envs/chess/test_chess.py +60 -0
- kaggle_environments/envs/connectx/connectx.ipynb +3186 -0
- kaggle_environments/envs/connectx/connectx.js +1 -1
- kaggle_environments/envs/connectx/connectx.json +15 -1
- kaggle_environments/envs/connectx/connectx.py +6 -23
- kaggle_environments/envs/connectx/test_connectx.py +70 -24
- kaggle_environments/envs/football/football.ipynb +75 -0
- kaggle_environments/envs/football/football.json +91 -0
- kaggle_environments/envs/football/football.py +277 -0
- kaggle_environments/envs/football/helpers.py +95 -0
- kaggle_environments/envs/football/test_football.py +360 -0
- kaggle_environments/envs/halite/__init__.py +0 -0
- kaggle_environments/envs/halite/halite.ipynb +44741 -0
- kaggle_environments/envs/halite/halite.js +199 -83
- kaggle_environments/envs/halite/halite.json +31 -18
- kaggle_environments/envs/halite/halite.py +164 -303
- kaggle_environments/envs/halite/helpers.py +720 -0
- kaggle_environments/envs/halite/test_halite.py +190 -0
- kaggle_environments/envs/hungry_geese/__init__.py +0 -0
- kaggle_environments/envs/{battlegeese/battlegeese.js → hungry_geese/hungry_geese.js} +38 -22
- kaggle_environments/envs/{battlegeese/battlegeese.json → hungry_geese/hungry_geese.json} +21 -14
- kaggle_environments/envs/hungry_geese/hungry_geese.py +316 -0
- kaggle_environments/envs/hungry_geese/test_hungry_geese.py +0 -0
- kaggle_environments/envs/identity/identity.json +6 -5
- kaggle_environments/envs/identity/identity.py +15 -2
- kaggle_environments/envs/kore_fleets/__init__.py +0 -0
- kaggle_environments/envs/kore_fleets/helpers.py +1005 -0
- kaggle_environments/envs/kore_fleets/kore_fleets.ipynb +114 -0
- kaggle_environments/envs/kore_fleets/kore_fleets.js +658 -0
- kaggle_environments/envs/kore_fleets/kore_fleets.json +164 -0
- kaggle_environments/envs/kore_fleets/kore_fleets.py +555 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/Bot.java +54 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/README.md +26 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/jars/hamcrest-core-1.3.jar +0 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/jars/junit-4.13.2.jar +0 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Board.java +518 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Cell.java +61 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Configuration.java +24 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Direction.java +166 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Fleet.java +72 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/KoreJson.java +97 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Observation.java +72 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Pair.java +13 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Player.java +68 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Point.java +65 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/Shipyard.java +70 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/kore/ShipyardAction.java +59 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/main.py +73 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/BoardTest.java +567 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/ConfigurationTest.java +25 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/KoreJsonTest.java +62 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/ObservationTest.java +46 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/PointTest.java +21 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/ShipyardTest.java +22 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/configuration.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/fullob.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/java/test/observation.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/python/__init__.py +0 -0
- kaggle_environments/envs/kore_fleets/starter_bots/python/main.py +27 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/Bot.ts +34 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/DoNothingBot.ts +12 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/MinerBot.ts +62 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/README.md +55 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/interpreter.ts +402 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Board.ts +514 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Cell.ts +63 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Configuration.ts +25 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Direction.ts +169 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Fleet.ts +76 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/KoreIO.ts +70 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Observation.ts +45 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Pair.ts +11 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Player.ts +68 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Point.ts +65 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/Shipyard.ts +72 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/kore/ShipyardAction.ts +58 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/main.py +73 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/miner.py +73 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/package.json +23 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/BoardTest.ts +551 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ConfigurationTest.ts +16 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ObservationTest.ts +33 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/PointTest.ts +17 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/ShipyardTest.ts +18 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/configuration.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/fullob.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/test/observation.json +1 -0
- kaggle_environments/envs/kore_fleets/starter_bots/ts/tsconfig.json +22 -0
- kaggle_environments/envs/kore_fleets/test_kore_fleets.py +331 -0
- kaggle_environments/envs/lux_ai_2021/README.md +3 -0
- kaggle_environments/envs/lux_ai_2021/__init__.py +0 -0
- kaggle_environments/envs/lux_ai_2021/agents.py +11 -0
- kaggle_environments/envs/lux_ai_2021/dimensions/754.js +2 -0
- kaggle_environments/envs/lux_ai_2021/dimensions/754.js.LICENSE.txt +296 -0
- kaggle_environments/envs/lux_ai_2021/dimensions/main.js +1 -0
- kaggle_environments/envs/lux_ai_2021/index.html +43 -0
- kaggle_environments/envs/lux_ai_2021/lux_ai_2021.json +100 -0
- kaggle_environments/envs/lux_ai_2021/lux_ai_2021.py +231 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/__init__.py +0 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_constants.js +6 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_constants.json +59 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/game_objects.js +145 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/io.js +14 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/kit.js +209 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/map.js +107 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/lux/parser.js +79 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/main.js +88 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/main.py +75 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/js_simple/simple.tar.gz +0 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/__init__.py +0 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/annotate.py +20 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/constants.py +25 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game.py +86 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_constants.json +59 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_constants.py +7 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_map.py +106 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/lux/game_objects.py +154 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/random_agent.py +38 -0
- kaggle_environments/envs/lux_ai_2021/test_agents/python/simple_agent.py +82 -0
- kaggle_environments/envs/lux_ai_2021/test_lux.py +19 -0
- kaggle_environments/envs/lux_ai_2021/testing.md +23 -0
- kaggle_environments/envs/lux_ai_2021/todo.md.og +18 -0
- kaggle_environments/envs/lux_ai_s3/README.md +21 -0
- kaggle_environments/envs/lux_ai_s3/agents.py +5 -0
- kaggle_environments/envs/lux_ai_s3/index.html +42 -0
- kaggle_environments/envs/lux_ai_s3/lux_ai_s3.json +47 -0
- kaggle_environments/envs/lux_ai_s3/lux_ai_s3.py +178 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/__init__.py +1 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/env.py +819 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/globals.py +9 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/params.py +101 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/profiler.py +141 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/pygame_render.py +222 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/spaces.py +27 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/state.py +464 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/utils.py +12 -0
- kaggle_environments/envs/lux_ai_s3/luxai_s3/wrappers.py +156 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/agent.py +78 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/__init__.py +0 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/kit.py +31 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/lux/utils.py +17 -0
- kaggle_environments/envs/lux_ai_s3/test_agents/python/main.py +66 -0
- kaggle_environments/envs/lux_ai_s3/test_lux.py +9 -0
- kaggle_environments/envs/mab/__init__.py +0 -0
- kaggle_environments/envs/mab/agents.py +12 -0
- kaggle_environments/envs/mab/mab.js +100 -0
- kaggle_environments/envs/mab/mab.json +74 -0
- kaggle_environments/envs/mab/mab.py +146 -0
- kaggle_environments/envs/open_spiel/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/chess/chess.js +441 -0
- kaggle_environments/envs/open_spiel/games/chess/image_config.jsonl +20 -0
- kaggle_environments/envs/open_spiel/games/chess/openings.jsonl +20 -0
- kaggle_environments/envs/open_spiel/games/connect_four/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/connect_four/connect_four.js +284 -0
- kaggle_environments/envs/open_spiel/games/connect_four/connect_four_proxy.py +86 -0
- kaggle_environments/envs/open_spiel/games/go/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/go/go.js +481 -0
- kaggle_environments/envs/open_spiel/games/go/go_proxy.py +99 -0
- kaggle_environments/envs/open_spiel/games/tic_tac_toe/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe.js +345 -0
- kaggle_environments/envs/open_spiel/games/tic_tac_toe/tic_tac_toe_proxy.py +98 -0
- kaggle_environments/envs/open_spiel/games/universal_poker/__init__.py +0 -0
- kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker.js +431 -0
- kaggle_environments/envs/open_spiel/games/universal_poker/universal_poker_proxy.py +159 -0
- kaggle_environments/envs/open_spiel/html_playthrough_generator.py +31 -0
- kaggle_environments/envs/open_spiel/observation.py +128 -0
- kaggle_environments/envs/open_spiel/open_spiel.py +565 -0
- kaggle_environments/envs/open_spiel/proxy.py +138 -0
- kaggle_environments/envs/open_spiel/test_open_spiel.py +191 -0
- kaggle_environments/envs/rps/__init__.py +0 -0
- kaggle_environments/envs/rps/agents.py +84 -0
- kaggle_environments/envs/rps/helpers.py +25 -0
- kaggle_environments/envs/rps/rps.js +117 -0
- kaggle_environments/envs/rps/rps.json +63 -0
- kaggle_environments/envs/rps/rps.py +90 -0
- kaggle_environments/envs/rps/test_rps.py +110 -0
- kaggle_environments/envs/rps/utils.py +7 -0
- kaggle_environments/envs/tictactoe/test_tictactoe.py +43 -77
- kaggle_environments/envs/tictactoe/tictactoe.ipynb +1397 -0
- kaggle_environments/envs/tictactoe/tictactoe.json +10 -2
- kaggle_environments/envs/tictactoe/tictactoe.py +1 -1
- kaggle_environments/errors.py +2 -4
- kaggle_environments/helpers.py +377 -0
- kaggle_environments/main.py +340 -0
- kaggle_environments/schemas.json +23 -18
- kaggle_environments/static/player.html +206 -74
- kaggle_environments/utils.py +46 -73
- {kaggle_environments-0.2.1.dist-info → kaggle_environments-1.20.1.dist-info}/METADATA +36 -114
- kaggle_environments-1.20.1.dist-info/RECORD +211 -0
- {kaggle_environments-0.2.1.dist-info → kaggle_environments-1.20.1.dist-info}/WHEEL +1 -2
- kaggle_environments-1.20.1.dist-info/entry_points.txt +3 -0
- kaggle_environments/envs/battlegeese/battlegeese.py +0 -223
- kaggle_environments/temp.py +0 -14
- kaggle_environments-0.2.1.dist-info/RECORD +0 -32
- kaggle_environments-0.2.1.dist-info/entry_points.txt +0 -3
- kaggle_environments-0.2.1.dist-info/top_level.txt +0 -1
- {kaggle_environments-0.2.1.dist-info → kaggle_environments-1.20.1.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const GAME_CONSTANTS = require('./game_constants');
|
|
2
|
+
const DIRECTIONS = GAME_CONSTANTS.DIRECTIONS;
|
|
3
|
+
class GameMap {
|
|
4
|
+
constructor(width, height) {
|
|
5
|
+
this.height = height;
|
|
6
|
+
this.width = width;
|
|
7
|
+
this.map = new Array(this.height);
|
|
8
|
+
|
|
9
|
+
for (let y = 0; y < this.height; y++) {
|
|
10
|
+
this.map[y] = new Array(this.width);
|
|
11
|
+
for (let x = 0; x < this.width; x++) {
|
|
12
|
+
this.map[y][x] = new Cell(x, y);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
getCellByPos(pos) {
|
|
17
|
+
return this.map[pos.y][pos.x];
|
|
18
|
+
}
|
|
19
|
+
getCell(x, y) {
|
|
20
|
+
return this.map[y][x];
|
|
21
|
+
}
|
|
22
|
+
_setResource(type, x, y, amount) {
|
|
23
|
+
const cell = this.getCell(x, y);
|
|
24
|
+
cell.resource = {
|
|
25
|
+
type: type,
|
|
26
|
+
amount: amount
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class Cell {
|
|
33
|
+
constructor(x, y) {
|
|
34
|
+
this.pos = new Position(x, y);
|
|
35
|
+
this.resource = null;
|
|
36
|
+
this.citytile = null;
|
|
37
|
+
this.road = 0;
|
|
38
|
+
}
|
|
39
|
+
hasResource() {
|
|
40
|
+
return this.resource !== null && this.resource.amount > 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class Position {
|
|
45
|
+
constructor(x, y) {
|
|
46
|
+
this.x = x;
|
|
47
|
+
this.y = y;
|
|
48
|
+
}
|
|
49
|
+
isAdjacent(pos) {
|
|
50
|
+
const dx = this.x - pos.x;
|
|
51
|
+
const dy = this.y - pos.y;
|
|
52
|
+
if (Math.abs(dx) + Math.abs(dy) > 1) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
equals(pos) {
|
|
58
|
+
return this.x === pos.x && this.y === pos.y;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
translate(direction, units) {
|
|
62
|
+
switch (direction) {
|
|
63
|
+
case DIRECTIONS.NORTH:
|
|
64
|
+
return new Position(this.x, this.y - units);
|
|
65
|
+
case DIRECTIONS.EAST:
|
|
66
|
+
return new Position(this.x + units, this.y);
|
|
67
|
+
case DIRECTIONS.SOUTH:
|
|
68
|
+
return new Position(this.x, this.y + units);
|
|
69
|
+
case DIRECTIONS.WEST:
|
|
70
|
+
return new Position(this.x - units, this.y);
|
|
71
|
+
case DIRECTIONS.CENTER:
|
|
72
|
+
return new Position(this.x, this.y);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Returns Manhattan distance to pos from this position */
|
|
77
|
+
distanceTo(pos) {
|
|
78
|
+
return Math.abs(pos.x - this.x) + Math.abs(pos.y - this.y);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Returns closest direction to targetPos, or null if staying put is best */
|
|
82
|
+
directionTo(targetPos) {
|
|
83
|
+
const checkDirections = [
|
|
84
|
+
DIRECTIONS.NORTH,
|
|
85
|
+
DIRECTIONS.EAST,
|
|
86
|
+
DIRECTIONS.SOUTH,
|
|
87
|
+
DIRECTIONS.WEST,
|
|
88
|
+
];
|
|
89
|
+
let closestDirection = DIRECTIONS.CENTER;
|
|
90
|
+
let closestDist = this.distanceTo(targetPos);
|
|
91
|
+
checkDirections.forEach((dir) => {
|
|
92
|
+
const newpos = this.translate(dir, 1);
|
|
93
|
+
const dist = targetPos.distanceTo(newpos);
|
|
94
|
+
if (dist < closestDist) {
|
|
95
|
+
closestDist = dist;
|
|
96
|
+
closestDirection = dir;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return closestDirection;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = {
|
|
104
|
+
GameMap,
|
|
105
|
+
Cell,
|
|
106
|
+
Position,
|
|
107
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser class to help parse a input line of data
|
|
3
|
+
*/
|
|
4
|
+
class Parser {
|
|
5
|
+
|
|
6
|
+
constructor(d = ',') {
|
|
7
|
+
this.delimiter = d;
|
|
8
|
+
return this.parse.bind(this);
|
|
9
|
+
}
|
|
10
|
+
setDelimeter(s) {
|
|
11
|
+
this.delimiter = s;
|
|
12
|
+
}
|
|
13
|
+
parse(str) {
|
|
14
|
+
return new Parsed(str, this.delimiter);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
class Parsed {
|
|
19
|
+
constructor(str, d) {
|
|
20
|
+
this.str = str;
|
|
21
|
+
this.contents = str.split(d);
|
|
22
|
+
|
|
23
|
+
// remove the last element if its empty string
|
|
24
|
+
if (this.contents[this.contents.length - 1] === '') {
|
|
25
|
+
this.contents = this.contents.slice(0, this.contents.length - 1);
|
|
26
|
+
}
|
|
27
|
+
this.index = 0;
|
|
28
|
+
}
|
|
29
|
+
_nextStr() {
|
|
30
|
+
if (this.index < this.contents.length) {
|
|
31
|
+
return this.contents[this.index++];
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
throw new Error("No more contents to consume from line")
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Returns the remainder of the line as an array of integers
|
|
38
|
+
nextIntArr() {
|
|
39
|
+
if (this.index < this.contents.length) {
|
|
40
|
+
let remainder = this.contents.slice(this.index, this.contents.length).map((val) => parseInt(val));
|
|
41
|
+
return remainder;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
throw new Error("No more contents to consume from line")
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
nextInt() {
|
|
48
|
+
let str = this._nextStr();
|
|
49
|
+
return parseInt(str);
|
|
50
|
+
}
|
|
51
|
+
// Returns the remainder of the line as an array of floats
|
|
52
|
+
nextFloatArr() {
|
|
53
|
+
if (this.index < this.contents.length) {
|
|
54
|
+
let remainder = this.contents.slice(this.index++).map((val) => parseFloat(val));
|
|
55
|
+
return remainder;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
throw new Error("No more contents to consume from line")
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
nextFloat() {
|
|
62
|
+
let str = this._nextStr();
|
|
63
|
+
return parseFloat(str);
|
|
64
|
+
}
|
|
65
|
+
// Returns the remainder of the line as an array of strings
|
|
66
|
+
nextStrArr() {
|
|
67
|
+
if (this.index < this.contents.length) {
|
|
68
|
+
let remainder = this.contents.slice(this.index++);
|
|
69
|
+
return remainder;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw new Error("No more contents to consume from line")
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
nextStr() {
|
|
76
|
+
return this._nextStr();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
module.exports = Parser
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const kit = require('./lux/kit');
|
|
2
|
+
const GAME_CONSTANTS = require('./lux/game_constants');
|
|
3
|
+
const DIRECTIONS = GAME_CONSTANTS.DIRECTIONS;
|
|
4
|
+
// create a new agent
|
|
5
|
+
const agent = new kit.Agent();
|
|
6
|
+
const annotate = kit.annotate;
|
|
7
|
+
|
|
8
|
+
// first initialize the agent, and then proceed to go in a loop waiting for updates and running the AI
|
|
9
|
+
agent.initialize().then(async () => {
|
|
10
|
+
while (true) {
|
|
11
|
+
/** Do not edit! **/
|
|
12
|
+
// wait for updates
|
|
13
|
+
await agent.update();
|
|
14
|
+
|
|
15
|
+
const actions = [];
|
|
16
|
+
const gameState = agent.gameState;
|
|
17
|
+
/** AI Code Goes Below! **/
|
|
18
|
+
|
|
19
|
+
const player = gameState.players[gameState.id];
|
|
20
|
+
const opponent = gameState.players[(gameState.id + 1) % 2];
|
|
21
|
+
const gameMap = gameState.map;
|
|
22
|
+
|
|
23
|
+
const resourceTiles = [];
|
|
24
|
+
for (let y = 0; y < gameMap.height; y++) {
|
|
25
|
+
for (let x = 0; x < gameMap.width; x++) {
|
|
26
|
+
const cell = gameMap.getCell(x, y);
|
|
27
|
+
if (cell.hasResource()) {
|
|
28
|
+
resourceTiles.push(cell);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// we iterate over all our units and do something with them
|
|
34
|
+
for (let i = 0; i < player.units.length; i++) {
|
|
35
|
+
const unit = player.units[i];
|
|
36
|
+
if (unit.isWorker() && unit.canAct()) {
|
|
37
|
+
if (unit.getCargoSpaceLeft() > 0) {
|
|
38
|
+
// if the unit is a worker and we have space in cargo, lets find the nearest resource tile and try to mine it
|
|
39
|
+
let closestResourceTile = null;
|
|
40
|
+
let closestDist = 9999999;
|
|
41
|
+
resourceTiles.forEach((cell) => {
|
|
42
|
+
if (cell.resource.type === GAME_CONSTANTS.RESOURCE_TYPES.COAL && !player.researchedCoal()) return;
|
|
43
|
+
if (cell.resource.type === GAME_CONSTANTS.RESOURCE_TYPES.URANIUM && !player.researchedUranium()) return;
|
|
44
|
+
const dist = cell.pos.distanceTo(unit.pos);
|
|
45
|
+
if (dist < closestDist) {
|
|
46
|
+
closestDist = dist;
|
|
47
|
+
closestResourceTile = cell;
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
if (closestResourceTile != null) {
|
|
51
|
+
const dir = unit.pos.directionTo(closestResourceTile.pos);
|
|
52
|
+
// move the unit in the direction towards the closest resource tile's position.
|
|
53
|
+
actions.push(unit.move(dir));
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
// if unit is a worker and there is no cargo space left, and we have cities, lets return to them
|
|
57
|
+
if (player.cities.size > 0) {
|
|
58
|
+
const city = player.cities.values().next().value
|
|
59
|
+
let closestDist = 999999;
|
|
60
|
+
let closestCityTile = null;
|
|
61
|
+
|
|
62
|
+
city.citytiles.forEach((citytile) => {
|
|
63
|
+
const dist = citytile.pos.distanceTo(unit.pos);
|
|
64
|
+
if (dist < closestDist) {
|
|
65
|
+
closestCityTile = citytile;
|
|
66
|
+
closestDist = dist;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
if (closestCityTile != null) {
|
|
70
|
+
const dir = unit.pos.directionTo(closestCityTile.pos);
|
|
71
|
+
actions.push(unit.move(dir));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// you can add debug annotations using the functions in the annotate object
|
|
79
|
+
// actions.push(annotate.circle(0, 0))
|
|
80
|
+
|
|
81
|
+
/** AI Code Goes Above! **/
|
|
82
|
+
|
|
83
|
+
/** Do not edit! **/
|
|
84
|
+
console.log(actions.join(","));
|
|
85
|
+
// end turn
|
|
86
|
+
agent.endTurn();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import atexit
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
from queue import Empty, Queue
|
|
5
|
+
from subprocess import PIPE, Popen
|
|
6
|
+
from threading import Thread
|
|
7
|
+
|
|
8
|
+
agent_processes = [None, None]
|
|
9
|
+
t = None
|
|
10
|
+
q = None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def cleanup_process():
|
|
14
|
+
global agent_processes
|
|
15
|
+
for proc in agent_processes:
|
|
16
|
+
if proc is not None:
|
|
17
|
+
proc.kill()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def enqueue_output(out, queue):
|
|
21
|
+
for line in iter(out.readline, b""):
|
|
22
|
+
queue.put(line)
|
|
23
|
+
out.close()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def js_agent(observation, configuration):
|
|
27
|
+
"""
|
|
28
|
+
a wrapper around a js agent
|
|
29
|
+
"""
|
|
30
|
+
global agent_processes, t, q
|
|
31
|
+
|
|
32
|
+
agent_process = agent_processes[observation.player]
|
|
33
|
+
### Do not edit ###
|
|
34
|
+
if agent_process is None:
|
|
35
|
+
if "__raw_path__" in configuration:
|
|
36
|
+
cwd = os.path.dirname(configuration["__raw_path__"])
|
|
37
|
+
else:
|
|
38
|
+
cwd = os.path.dirname(__file__)
|
|
39
|
+
agent_process = Popen(["node", "main.js"], stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=cwd)
|
|
40
|
+
agent_processes[observation.player] = agent_process
|
|
41
|
+
atexit.register(cleanup_process)
|
|
42
|
+
|
|
43
|
+
# following 4 lines from https://stackoverflow.com/questions/375427/a-non-blocking-read-on-a-subprocess-pipe-in-python
|
|
44
|
+
q = Queue()
|
|
45
|
+
t = Thread(target=enqueue_output, args=(agent_process.stderr, q))
|
|
46
|
+
t.daemon = True # thread dies with the program
|
|
47
|
+
t.start()
|
|
48
|
+
if observation.step == 0:
|
|
49
|
+
# fixes bug where updates array is shared, but the first update is agent dependent actually
|
|
50
|
+
observation["updates"][0] = f"{observation.player}"
|
|
51
|
+
|
|
52
|
+
# print observations to agent
|
|
53
|
+
agent_process.stdin.write(("\n".join(observation["updates"]) + "\n").encode())
|
|
54
|
+
agent_process.stdin.flush()
|
|
55
|
+
|
|
56
|
+
# wait for data written to stdout
|
|
57
|
+
agent1res = (agent_process.stdout.readline()).decode()
|
|
58
|
+
_end_res = (agent_process.stdout.readline()).decode()
|
|
59
|
+
|
|
60
|
+
while True:
|
|
61
|
+
try:
|
|
62
|
+
line = q.get_nowait()
|
|
63
|
+
except Empty:
|
|
64
|
+
# no standard error received, break
|
|
65
|
+
break
|
|
66
|
+
else:
|
|
67
|
+
# standard error output received, print it out
|
|
68
|
+
print(line.decode(), file=sys.stderr, end="")
|
|
69
|
+
|
|
70
|
+
outputs = agent1res.split("\n")[0].split(",")
|
|
71
|
+
actions = []
|
|
72
|
+
for cmd in outputs:
|
|
73
|
+
if cmd != "":
|
|
74
|
+
actions.append(cmd)
|
|
75
|
+
return actions
|
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
def circle(x: int, y: int) -> str:
|
|
2
|
+
return f"dc {x} {y}"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def x(x: int, y: int) -> str:
|
|
6
|
+
return f"dx {x} {y}"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def line(x1: int, y1: int, x2: int, y2: int) -> str:
|
|
10
|
+
return f"dl {x1} {y1} {x2} {y2}"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# text at cell on map
|
|
14
|
+
def text(x: int, y: int, message: str, fontsize: int = 16) -> str:
|
|
15
|
+
return f"dt {x} {y} {fontsize} '{message}'"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# text besides map
|
|
19
|
+
def sidetext(message: str) -> str:
|
|
20
|
+
return f"dst '{message}'"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class Constants:
|
|
2
|
+
class INPUT_CONSTANTS:
|
|
3
|
+
RESEARCH_POINTS = "rp"
|
|
4
|
+
RESOURCES = "r"
|
|
5
|
+
UNITS = "u"
|
|
6
|
+
CITY = "c"
|
|
7
|
+
CITY_TILES = "ct"
|
|
8
|
+
ROADS = "ccd"
|
|
9
|
+
DONE = "D_DONE"
|
|
10
|
+
|
|
11
|
+
class DIRECTIONS:
|
|
12
|
+
NORTH = "n"
|
|
13
|
+
WEST = "w"
|
|
14
|
+
SOUTH = "s"
|
|
15
|
+
EAST = "e"
|
|
16
|
+
CENTER = "c"
|
|
17
|
+
|
|
18
|
+
class UNIT_TYPES:
|
|
19
|
+
WORKER = 0
|
|
20
|
+
CART = 1
|
|
21
|
+
|
|
22
|
+
class RESOURCE_TYPES:
|
|
23
|
+
WOOD = "wood"
|
|
24
|
+
URANIUM = "uranium"
|
|
25
|
+
COAL = "coal"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from .constants import Constants
|
|
2
|
+
from .game_map import GameMap
|
|
3
|
+
from .game_objects import City, Player, Unit
|
|
4
|
+
|
|
5
|
+
INPUT_CONSTANTS = Constants.INPUT_CONSTANTS
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Game:
|
|
9
|
+
def _initialize(self, messages):
|
|
10
|
+
"""
|
|
11
|
+
initialize state
|
|
12
|
+
"""
|
|
13
|
+
self.id = int(messages[0])
|
|
14
|
+
self.turn = -1
|
|
15
|
+
# get some other necessary initial input
|
|
16
|
+
mapInfo = messages[1].split(" ")
|
|
17
|
+
self.map_width = int(mapInfo[0])
|
|
18
|
+
self.map_height = int(mapInfo[1])
|
|
19
|
+
self.map = GameMap(self.map_width, self.map_height)
|
|
20
|
+
self.players = [Player(0), Player(1)]
|
|
21
|
+
|
|
22
|
+
def _end_turn(self):
|
|
23
|
+
print("D_FINISH")
|
|
24
|
+
|
|
25
|
+
def _reset_player_states(self):
|
|
26
|
+
self.players[0].units = []
|
|
27
|
+
self.players[0].cities = {}
|
|
28
|
+
self.players[0].city_tile_count = 0
|
|
29
|
+
self.players[1].units = []
|
|
30
|
+
self.players[1].cities = {}
|
|
31
|
+
self.players[1].city_tile_count = 0
|
|
32
|
+
|
|
33
|
+
def _update(self, messages):
|
|
34
|
+
"""
|
|
35
|
+
update state
|
|
36
|
+
"""
|
|
37
|
+
self.map = GameMap(self.map_width, self.map_height)
|
|
38
|
+
self.turn += 1
|
|
39
|
+
self._reset_player_states()
|
|
40
|
+
|
|
41
|
+
for update in messages:
|
|
42
|
+
if update == "D_DONE":
|
|
43
|
+
break
|
|
44
|
+
strs = update.split(" ")
|
|
45
|
+
input_identifier = strs[0]
|
|
46
|
+
if input_identifier == INPUT_CONSTANTS.RESEARCH_POINTS:
|
|
47
|
+
team = int(strs[1])
|
|
48
|
+
self.players[team].research_points = int(strs[2])
|
|
49
|
+
elif input_identifier == INPUT_CONSTANTS.RESOURCES:
|
|
50
|
+
r_type = strs[1]
|
|
51
|
+
x = int(strs[2])
|
|
52
|
+
y = int(strs[3])
|
|
53
|
+
amt = int(float(strs[4]))
|
|
54
|
+
self.map._setResource(r_type, x, y, amt)
|
|
55
|
+
elif input_identifier == INPUT_CONSTANTS.UNITS:
|
|
56
|
+
unittype = int(strs[1])
|
|
57
|
+
team = int(strs[2])
|
|
58
|
+
unitid = strs[3]
|
|
59
|
+
x = int(strs[4])
|
|
60
|
+
y = int(strs[5])
|
|
61
|
+
cooldown = float(strs[6])
|
|
62
|
+
wood = int(strs[7])
|
|
63
|
+
coal = int(strs[8])
|
|
64
|
+
uranium = int(strs[9])
|
|
65
|
+
self.players[team].units.append(Unit(team, unittype, unitid, x, y, cooldown, wood, coal, uranium))
|
|
66
|
+
elif input_identifier == INPUT_CONSTANTS.CITY:
|
|
67
|
+
team = int(strs[1])
|
|
68
|
+
cityid = strs[2]
|
|
69
|
+
fuel = float(strs[3])
|
|
70
|
+
lightupkeep = float(strs[4])
|
|
71
|
+
self.players[team].cities[cityid] = City(team, cityid, fuel, lightupkeep)
|
|
72
|
+
elif input_identifier == INPUT_CONSTANTS.CITY_TILES:
|
|
73
|
+
team = int(strs[1])
|
|
74
|
+
cityid = strs[2]
|
|
75
|
+
x = int(strs[3])
|
|
76
|
+
y = int(strs[4])
|
|
77
|
+
cooldown = float(strs[5])
|
|
78
|
+
city = self.players[team].cities[cityid]
|
|
79
|
+
citytile = city._add_city_tile(x, y, cooldown)
|
|
80
|
+
self.map.get_cell(x, y).citytile = citytile
|
|
81
|
+
self.players[team].city_tile_count += 1
|
|
82
|
+
elif input_identifier == INPUT_CONSTANTS.ROADS:
|
|
83
|
+
x = int(strs[1])
|
|
84
|
+
y = int(strs[2])
|
|
85
|
+
road = float(strs[3])
|
|
86
|
+
self.map.get_cell(x, y).road = road
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"UNIT_TYPES": {
|
|
3
|
+
"WORKER": 0,
|
|
4
|
+
"CART": 1
|
|
5
|
+
},
|
|
6
|
+
"RESOURCE_TYPES": {
|
|
7
|
+
"WOOD": "wood",
|
|
8
|
+
"COAL": "coal",
|
|
9
|
+
"URANIUM": "uranium"
|
|
10
|
+
},
|
|
11
|
+
"DIRECTIONS": {
|
|
12
|
+
"NORTH": "n",
|
|
13
|
+
"WEST": "w",
|
|
14
|
+
"EAST": "e",
|
|
15
|
+
"SOUTH": "s",
|
|
16
|
+
"CENTER": "c"
|
|
17
|
+
},
|
|
18
|
+
"PARAMETERS": {
|
|
19
|
+
"DAY_LENGTH": 30,
|
|
20
|
+
"NIGHT_LENGTH": 10,
|
|
21
|
+
"MAX_DAYS": 360,
|
|
22
|
+
"LIGHT_UPKEEP": {
|
|
23
|
+
"CITY": 30,
|
|
24
|
+
"WORKER": 4,
|
|
25
|
+
"CART": 10
|
|
26
|
+
},
|
|
27
|
+
"WOOD_GROWTH_RATE": 1.01,
|
|
28
|
+
"MAX_WOOD_AMOUNT": 500,
|
|
29
|
+
"CITY_BUILD_COST": 100,
|
|
30
|
+
"CITY_ADJACENCY_BONUS": 5,
|
|
31
|
+
"RESOURCE_CAPACITY": {
|
|
32
|
+
"WORKER": 100,
|
|
33
|
+
"CART": 2000
|
|
34
|
+
},
|
|
35
|
+
"WORKER_COLLECTION_RATE": {
|
|
36
|
+
"WOOD": 20,
|
|
37
|
+
"COAL": 5,
|
|
38
|
+
"URANIUM": 2
|
|
39
|
+
},
|
|
40
|
+
"RESOURCE_TO_FUEL_RATE": {
|
|
41
|
+
"WOOD": 1,
|
|
42
|
+
"COAL": 10,
|
|
43
|
+
"URANIUM": 40
|
|
44
|
+
},
|
|
45
|
+
"RESEARCH_REQUIREMENTS": {
|
|
46
|
+
"COAL": 50,
|
|
47
|
+
"URANIUM": 200
|
|
48
|
+
},
|
|
49
|
+
"CITY_ACTION_COOLDOWN": 10,
|
|
50
|
+
"UNIT_ACTION_COOLDOWN": {
|
|
51
|
+
"CART": 3,
|
|
52
|
+
"WORKER": 2
|
|
53
|
+
},
|
|
54
|
+
"MAX_ROAD": 6,
|
|
55
|
+
"MIN_ROAD": 0,
|
|
56
|
+
"CART_ROAD_DEVELOPMENT_RATE": 0.5,
|
|
57
|
+
"PILLAGE_RATE": 0.5
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from .constants import Constants
|
|
4
|
+
|
|
5
|
+
DIRECTIONS = Constants.DIRECTIONS
|
|
6
|
+
RESOURCE_TYPES = Constants.RESOURCE_TYPES
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Resource:
|
|
10
|
+
def __init__(self, r_type: str, amount: int):
|
|
11
|
+
self.type = r_type
|
|
12
|
+
self.amount = amount
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Cell:
|
|
16
|
+
def __init__(self, x, y):
|
|
17
|
+
self.pos = Position(x, y)
|
|
18
|
+
self.resource: Resource = None
|
|
19
|
+
self.citytile = None
|
|
20
|
+
self.road = 0
|
|
21
|
+
|
|
22
|
+
def has_resource(self):
|
|
23
|
+
return self.resource is not None and self.resource.amount > 0
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class GameMap:
|
|
27
|
+
def __init__(self, width, height):
|
|
28
|
+
self.height = height
|
|
29
|
+
self.width = width
|
|
30
|
+
self.map: List[List[Cell]] = [None] * height
|
|
31
|
+
for y in range(0, self.height):
|
|
32
|
+
self.map[y] = [None] * width
|
|
33
|
+
for x in range(0, self.width):
|
|
34
|
+
self.map[y][x] = Cell(x, y)
|
|
35
|
+
|
|
36
|
+
def get_cell_by_pos(self, pos) -> Cell:
|
|
37
|
+
return self.map[pos.y][pos.x]
|
|
38
|
+
|
|
39
|
+
def get_cell(self, x, y) -> Cell:
|
|
40
|
+
return self.map[y][x]
|
|
41
|
+
|
|
42
|
+
def _setResource(self, r_type, x, y, amount):
|
|
43
|
+
"""
|
|
44
|
+
do not use this function, this is for internal tracking of state
|
|
45
|
+
"""
|
|
46
|
+
cell = self.get_cell(x, y)
|
|
47
|
+
cell.resource = Resource(r_type, amount)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Position:
|
|
51
|
+
def __init__(self, x, y):
|
|
52
|
+
self.x = x
|
|
53
|
+
self.y = y
|
|
54
|
+
|
|
55
|
+
def __sub__(self, pos) -> int:
|
|
56
|
+
return abs(pos.x - self.x) + abs(pos.y - self.y)
|
|
57
|
+
|
|
58
|
+
def distance_to(self, pos):
|
|
59
|
+
"""
|
|
60
|
+
Returns Manhattan (L1/grid) distance to pos
|
|
61
|
+
"""
|
|
62
|
+
return self - pos
|
|
63
|
+
|
|
64
|
+
def is_adjacent(self, pos):
|
|
65
|
+
return (self - pos) <= 1
|
|
66
|
+
|
|
67
|
+
def __eq__(self, pos) -> bool:
|
|
68
|
+
return self.x == pos.x and self.y == pos.y
|
|
69
|
+
|
|
70
|
+
def equals(self, pos):
|
|
71
|
+
return self == pos
|
|
72
|
+
|
|
73
|
+
def translate(self, direction, units) -> "Position":
|
|
74
|
+
if direction == DIRECTIONS.NORTH:
|
|
75
|
+
return Position(self.x, self.y - units)
|
|
76
|
+
elif direction == DIRECTIONS.EAST:
|
|
77
|
+
return Position(self.x + units, self.y)
|
|
78
|
+
elif direction == DIRECTIONS.SOUTH:
|
|
79
|
+
return Position(self.x, self.y + units)
|
|
80
|
+
elif direction == DIRECTIONS.WEST:
|
|
81
|
+
return Position(self.x - units, self.y)
|
|
82
|
+
elif direction == DIRECTIONS.CENTER:
|
|
83
|
+
return Position(self.x, self.y)
|
|
84
|
+
|
|
85
|
+
def direction_to(self, target_pos: "Position") -> DIRECTIONS:
|
|
86
|
+
"""
|
|
87
|
+
Return closest position to target_pos from this position
|
|
88
|
+
"""
|
|
89
|
+
check_dirs = [
|
|
90
|
+
DIRECTIONS.NORTH,
|
|
91
|
+
DIRECTIONS.EAST,
|
|
92
|
+
DIRECTIONS.SOUTH,
|
|
93
|
+
DIRECTIONS.WEST,
|
|
94
|
+
]
|
|
95
|
+
closest_dist = self.distance_to(target_pos)
|
|
96
|
+
closest_dir = DIRECTIONS.CENTER
|
|
97
|
+
for direction in check_dirs:
|
|
98
|
+
newpos = self.translate(direction, 1)
|
|
99
|
+
dist = target_pos.distance_to(newpos)
|
|
100
|
+
if dist < closest_dist:
|
|
101
|
+
closest_dir = direction
|
|
102
|
+
closest_dist = dist
|
|
103
|
+
return closest_dir
|
|
104
|
+
|
|
105
|
+
def __str__(self) -> str:
|
|
106
|
+
return f"({self.x}, {self.y})"
|